All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] nfsd: add support for NFSv4 callbacks over IPv6
@ 2009-06-17 18:15 Jeff Layton
  2009-06-17 18:15 ` [PATCH 1/4] nfsd: convert nfs4_callback struct to hold address in sockaddr_storage Jeff Layton
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Jeff Layton @ 2009-06-17 18:15 UTC (permalink / raw)
  To: linux-nfs; +Cc: chuck.lever, bfields

This patchset is a first pass at adding IPv6 callback channel support
for knfsd. The set is fairly straightforward, but it does require a
number of changes to server side NFSv4 related structs that store
addresses in places that are only suitable for IPv4 addresses.

I've tested this by having Linux and OpenSolaris clients mount the
server over an IPv6 socket, get a delegation and ensure that the server
can recall that delegation. It all seems to work as expected. IPv4
callbacks also seem to continue to work correctly.

This patchset does change the some of the new 4.1 functions
(nfsd4_exchange_id in particular). Those changes are untested as of yet
but I'll see if I can do so if the approach in this set seems
reasonable.

Comments welcome...

Jeff Layton (4):
  nfsd: convert nfs4_callback struct to hold address in
    sockaddr_storage
  nfsd: break out setclientid port parsing into separate routine
  nfsd: make nfs4_client->cl_addr a struct sockaddr_storage
  nfsd: add support for NFSv4 callbacks over IPv6

 fs/nfsd/nfs4callback.c     |   11 +--
 fs/nfsd/nfs4state.c        |  220 ++++++++++++++++++++++++++++++++++++-------
 include/linux/nfsd/state.h |    6 +-
 3 files changed, 189 insertions(+), 48 deletions(-)


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/4] nfsd: convert nfs4_callback struct to hold address in sockaddr_storage
  2009-06-17 18:15 [PATCH 0/4] nfsd: add support for NFSv4 callbacks over IPv6 Jeff Layton
@ 2009-06-17 18:15 ` Jeff Layton
  2009-06-17 18:15 ` [PATCH 2/4] nfsd: break out setclientid port parsing into separate routine Jeff Layton
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2009-06-17 18:15 UTC (permalink / raw)
  To: linux-nfs; +Cc: chuck.lever, bfields

...rather than as a separate address and port fields. This will be
necessary for implementing callbacks over IPv6.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/nfsd/nfs4callback.c     |   11 ++---------
 fs/nfsd/nfs4state.c        |   13 +++++++++----
 include/linux/nfsd/state.h |    4 ++--
 3 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index f4fab69..0358563 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -368,7 +368,6 @@ static int max_cb_time(void)
 
 int setup_callback_client(struct nfs4_client *clp)
 {
-	struct sockaddr_in	addr;
 	struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
 	struct rpc_timeout	timeparms = {
 		.to_initval	= max_cb_time(),
@@ -376,8 +375,8 @@ int setup_callback_client(struct nfs4_client *clp)
 	};
 	struct rpc_create_args args = {
 		.protocol	= IPPROTO_TCP,
-		.address	= (struct sockaddr *)&addr,
-		.addrsize	= sizeof(addr),
+		.address	= (struct sockaddr *) &cb->cb_addr,
+		.addrsize	= cb->cb_addrlen,
 		.timeout	= &timeparms,
 		.program	= &cb_program,
 		.prognumber	= cb->cb_prog,
@@ -391,12 +390,6 @@ int setup_callback_client(struct nfs4_client *clp)
 	if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
 		return -EINVAL;
 
-	/* Initialize address */
-	memset(&addr, 0, sizeof(addr));
-	addr.sin_family = AF_INET;
-	addr.sin_port = htons(cb->cb_port);
-	addr.sin_addr.s_addr = htonl(cb->cb_addr);
-
 	/* Create RPC client */
 	client = rpc_create(&args);
 	if (IS_ERR(client)) {
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d5caf2a..edb03d4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -932,7 +932,7 @@ parse_octet(unsigned int *lenp, char **addrp)
 
 /* parse and set the setclientid ipv4 callback address */
 static int
-parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp)
+parse_ipv4(unsigned int addr_len, char *addr_val, struct sockaddr_in *s4)
 {
 	int temp = 0;
 	u32 cbaddr = 0;
@@ -941,6 +941,8 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne
 	char *addr = addr_val;
 	int i, shift;
 
+	s4->sin_family = AF_INET;
+
 	/* ipaddress */
 	shift = 24;
 	for(i = 4; i > 0  ; i--) {
@@ -951,7 +953,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne
 		if (shift > 0)
 		shift -= 8;
 	}
-	*cbaddrp = cbaddr;
+	s4->sin_addr.s_addr = htonl(cbaddr);
 
 	/* port */
 	shift = 8;
@@ -963,7 +965,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne
 		if (shift > 0)
 			shift -= 8;
 	}
-	*cbportp = cbport;
+	s4->sin_port = htons(cbport);
 	return 1;
 }
 
@@ -977,12 +979,15 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
 		goto out_err;
 
 	if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val,
-	                 &cb->cb_addr, &cb->cb_port)))
+			  (struct sockaddr_in *) &cb->cb_addr)))
 		goto out_err;
+	cb->cb_addrlen = sizeof(struct sockaddr_in);
 	cb->cb_prog = se->se_callback_prog;
 	cb->cb_ident = se->se_callback_ident;
 	return;
 out_err:
+	cb->cb_addr.ss_family = AF_UNSPEC;
+	cb->cb_addrlen = 0;
 	dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
 		"will not receive delegations\n",
 		clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 0ae4752..95a925c 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -81,8 +81,8 @@ struct nfs4_delegation {
 /* client delegation callback info */
 struct nfs4_cb_conn {
 	/* SETCLIENTID info */
-	u32                     cb_addr;
-	unsigned short          cb_port;
+	struct sockaddr_storage	cb_addr;
+	size_t			cb_addrlen;
 	u32                     cb_prog;
 	u32                     cb_ident;
 	/* RPC client info */
-- 
1.6.0.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/4] nfsd: break out setclientid port parsing into separate routine
  2009-06-17 18:15 [PATCH 0/4] nfsd: add support for NFSv4 callbacks over IPv6 Jeff Layton
  2009-06-17 18:15 ` [PATCH 1/4] nfsd: convert nfs4_callback struct to hold address in sockaddr_storage Jeff Layton
@ 2009-06-17 18:15 ` Jeff Layton
  2009-06-17 18:15 ` [PATCH 3/4] nfsd: make nfs4_client->cl_addr a struct sockaddr_storage Jeff Layton
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2009-06-17 18:15 UTC (permalink / raw)
  To: linux-nfs; +Cc: chuck.lever, bfields

...and change the parse_ipv4 routine to be a little more efficient with
the stack.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/nfsd/nfs4state.c |   46 ++++++++++++++++++++++++++++++----------------
 1 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index edb03d4..6a12219 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -930,15 +930,40 @@ parse_octet(unsigned int *lenp, char **addrp)
 	return n;
 }
 
+/*
+ * Parse port out of setclientid callback address
+ *
+ * @addrlen: remaining length of address string
+ * @addr: pointer to first port octet in address string
+ * @sa: pointer to port field in sockaddr
+ *
+ * Parse the port portion of a setclientid callback address. Returns true on
+ * success and false on failure.
+ */
+static bool
+parse_port(unsigned int addrlen, char *addr, __be16 *port)
+{
+	int temp = 0, i, shift = 8;
+	u16 cbport = 0;
+
+	for (i = 2; i > 0; i--) {
+		temp = parse_octet(&addrlen, &addr);
+		if (temp < 0)
+			return 0;
+		cbport |= (temp << shift);
+		if (shift > 0)
+			shift -= 8;
+	}
+	*port = htons(cbport);
+	return 1;
+}
+
 /* parse and set the setclientid ipv4 callback address */
 static int
-parse_ipv4(unsigned int addr_len, char *addr_val, struct sockaddr_in *s4)
+parse_ipv4(unsigned int addrlen, char *addr, struct sockaddr_in *s4)
 {
 	int temp = 0;
 	u32 cbaddr = 0;
-	u16 cbport = 0;
-	u32 addrlen = addr_len;
-	char *addr = addr_val;
 	int i, shift;
 
 	s4->sin_family = AF_INET;
@@ -955,18 +980,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, struct sockaddr_in *s4)
 	}
 	s4->sin_addr.s_addr = htonl(cbaddr);
 
-	/* port */
-	shift = 8;
-	for(i = 2; i > 0  ; i--) {
-		if ((temp = parse_octet(&addrlen, &addr)) < 0) {
-			return 0;
-		}
-		cbport |= (temp << shift);
-		if (shift > 0)
-			shift -= 8;
-	}
-	s4->sin_port = htons(cbport);
-	return 1;
+	return parse_port(addrlen, addr, &s4->sin_port);
 }
 
 static void
-- 
1.6.0.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/4] nfsd: make nfs4_client->cl_addr a struct sockaddr_storage
  2009-06-17 18:15 [PATCH 0/4] nfsd: add support for NFSv4 callbacks over IPv6 Jeff Layton
  2009-06-17 18:15 ` [PATCH 1/4] nfsd: convert nfs4_callback struct to hold address in sockaddr_storage Jeff Layton
  2009-06-17 18:15 ` [PATCH 2/4] nfsd: break out setclientid port parsing into separate routine Jeff Layton
@ 2009-06-17 18:15 ` Jeff Layton
  2009-06-17 18:15 ` [PATCH 4/4] nfsd: add support for NFSv4 callbacks over IPv6 Jeff Layton
  2009-06-17 18:47 ` [PATCH 0/4] " J. Bruce Fields
  4 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2009-06-17 18:15 UTC (permalink / raw)
  To: linux-nfs; +Cc: chuck.lever, bfields

It's currently a __be32, which isn't big enough to hold an IPv6 address.
While we're at it, add some new routines for comparing and copying
cl_addr's, and a function for formatting a cl_addr into a string.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/nfsd/nfs4state.c        |   89 +++++++++++++++++++++++++++++++++++++-------
 include/linux/nfsd/state.h |    2 +-
 2 files changed, 76 insertions(+), 15 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6a12219..f1caddd 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1198,6 +1198,62 @@ nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid)
 	clid->flags = new->cl_exchange_flags;
 }
 
+/* Returns true if addresses are equal (ignoring port, scope, etc) */
+static bool
+cl_addr_equal(struct sockaddr *a, struct sockaddr *b)
+{
+	struct sockaddr_in *a4, *b4;
+
+	if (a->sa_family != b->sa_family)
+		return false;
+
+	switch (a->sa_family) {
+	case AF_INET:
+		a4 = (struct sockaddr_in *) a;
+		b4 = (struct sockaddr_in *) b;
+		return (a4->sin_addr.s_addr == b4->sin_addr.s_addr);
+	}
+
+	/* not sure how to compare, so just return false */
+	return false;
+}
+
+/* Given a sockaddr, fill in the cl_addr -- ignore port, scope, etc */
+static void
+cl_addr_copy(struct sockaddr *dst, struct sockaddr *src)
+{
+	struct sockaddr_in *s4, *d4;
+
+	dst->sa_family = src->sa_family;
+
+	switch (dst->sa_family) {
+	case AF_INET:
+		s4 = (struct sockaddr_in *) src;
+		d4 = (struct sockaddr_in *) dst;
+		d4->sin_addr.s_addr = s4->sin_addr.s_addr;
+		return;
+	default:
+		dst->sa_family = AF_UNSPEC;
+	}
+}
+
+/* format the cl_addr as text and stuff it into buf. Don't go beyond size. */
+static void
+cl_addr_snprintf(char *buf, size_t size, struct sockaddr *sa)
+{
+	switch (sa->sa_family) {
+	case AF_INET:
+		snprintf(buf, size, "%pI4",
+			 &((struct sockaddr_in *) sa)->sin_addr.s_addr);
+		break;
+	default:
+		snprintf(buf, size, "(family=%hu)", sa->sa_family);
+	}
+
+	/* forcibly NULL terminate string, just in case */
+	buf[size - 1] = '\0';
+}
+
 __be32
 nfsd4_exchange_id(struct svc_rqst *rqstp,
 		  struct nfsd4_compound_state *cstate,
@@ -1207,13 +1263,15 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 	int status;
 	unsigned int		strhashval;
 	char			dname[HEXDIR_LEN];
+	char			addr_str[INET_ADDRSTRLEN];
 	nfs4_verifier		verf = exid->verifier;
-	u32			ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr;
+	struct sockaddr		*sa = svc_addr(rqstp);
 
+	cl_addr_snprintf(addr_str, INET_ADDRSTRLEN, sa);
 	dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
-		" ip_addr=%u flags %x, spa_how %d\n",
+		"ip_addr=%s flags %x, spa_how %d\n",
 		__func__, rqstp, exid, exid->clname.len, exid->clname.data,
-		ip_addr, exid->flags, exid->spa_how);
+		addr_str, exid->flags, exid->spa_how);
 
 	if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A))
 		return nfserr_inval;
@@ -1261,7 +1319,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 			expire_client(conf);
 			goto out_new;
 		}
-		if (ip_addr != conf->cl_addr &&
+		if (!cl_addr_equal((struct sockaddr *) &conf->cl_addr, sa) &&
 		    !(exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A)) {
 			/* Client collision. 18.35.4 case 3 */
 			status = nfserr_clid_inuse;
@@ -1308,7 +1366,7 @@ out_new:
 
 	copy_verf(new, &verf);
 	copy_cred(&new->cl_cred, &rqstp->rq_cred);
-	new->cl_addr = ip_addr;
+	cl_addr_copy((struct sockaddr *) &new->cl_addr, sa);
 	gen_clid(new);
 	gen_confirm(new);
 	add_to_unconfirmed(new, strhashval);
@@ -1362,7 +1420,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 		     struct nfsd4_compound_state *cstate,
 		     struct nfsd4_create_session *cr_ses)
 {
-	u32 ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr;
+	struct sockaddr *sa = svc_addr(rqstp);
 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
 	struct nfs4_client *conf, *unconf;
 	struct nfsd4_slot *slot = NULL;
@@ -1393,7 +1451,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 		conf->cl_slot.sl_seqid++;
 	} else if (unconf) {
 		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
-		    (ip_addr != unconf->cl_addr)) {
+		    !cl_addr_equal(sa, (struct sockaddr *) &unconf->cl_addr)) {
 			status = nfserr_clid_inuse;
 			goto out;
 		}
@@ -1541,7 +1599,7 @@ __be32
 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		  struct nfsd4_setclientid *setclid)
 {
-	struct sockaddr_in	*sin = svc_addr_in(rqstp);
+	struct sockaddr		*sa = svc_addr(rqstp);
 	struct xdr_netobj 	clname = { 
 		.len = setclid->se_namelen,
 		.data = setclid->se_name,
@@ -1573,8 +1631,11 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		/* RFC 3530 14.2.33 CASE 0: */
 		status = nfserr_clid_inuse;
 		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
-			dprintk("NFSD: setclientid: string in use by client"
-				" at %pI4\n", &conf->cl_addr);
+			char addr_str[INET_ADDRSTRLEN];
+			cl_addr_snprintf(addr_str, INET_ADDRSTRLEN,
+					 (struct sockaddr *) &conf->cl_addr);
+			dprintk("NFSD: setclientid: string in use by client "
+				"at %s\n", addr_str);
 			goto out;
 		}
 	}
@@ -1636,7 +1697,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		gen_clid(new);
 	}
 	copy_verf(new, &clverifier);
-	new->cl_addr = sin->sin_addr.s_addr;
+	cl_addr_copy((struct sockaddr *) &new->cl_addr, sa);
 	new->cl_flavor = rqstp->rq_flavor;
 	princ = svc_gss_principal(rqstp);
 	if (princ) {
@@ -1670,7 +1731,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
 			 struct nfsd4_compound_state *cstate,
 			 struct nfsd4_setclientid_confirm *setclientid_confirm)
 {
-	struct sockaddr_in *sin = svc_addr_in(rqstp);
+	struct sockaddr *sa = svc_addr(rqstp);
 	struct nfs4_client *conf, *unconf;
 	nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
 	clientid_t * clid = &setclientid_confirm->sc_clientid;
@@ -1689,9 +1750,9 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
 	unconf = find_unconfirmed_client(clid);
 
 	status = nfserr_clid_inuse;
-	if (conf && conf->cl_addr != sin->sin_addr.s_addr)
+	if (conf && !cl_addr_equal((struct sockaddr *) &conf->cl_addr, sa))
 		goto out;
-	if (unconf && unconf->cl_addr != sin->sin_addr.s_addr)
+	if (unconf && !cl_addr_equal((struct sockaddr *) &unconf->cl_addr, sa))
 		goto out;
 
 	/*
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 95a925c..d9728b9 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -179,7 +179,7 @@ struct nfs4_client {
 	char                    cl_recdir[HEXDIR_LEN]; /* recovery dir */
 	nfs4_verifier		cl_verifier; 	/* generated by client */
 	time_t                  cl_time;        /* time of last lease renewal */
-	__be32			cl_addr; 	/* client ipaddress */
+	struct sockaddr_storage	cl_addr; 	/* client ipaddress */
 	u32			cl_flavor;	/* setclientid pseudoflavor */
 	char			*cl_principal;	/* setclientid principal name */
 	struct svc_cred		cl_cred; 	/* setclientid principal */
-- 
1.6.0.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/4] nfsd: add support for NFSv4 callbacks over IPv6
  2009-06-17 18:15 [PATCH 0/4] nfsd: add support for NFSv4 callbacks over IPv6 Jeff Layton
                   ` (2 preceding siblings ...)
  2009-06-17 18:15 ` [PATCH 3/4] nfsd: make nfs4_client->cl_addr a struct sockaddr_storage Jeff Layton
@ 2009-06-17 18:15 ` Jeff Layton
  2009-06-17 18:47 ` [PATCH 0/4] " J. Bruce Fields
  4 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2009-06-17 18:15 UTC (permalink / raw)
  To: linux-nfs; +Cc: chuck.lever, bfields

The framework to add this is all in place. Now, add the code to allow
support for establishing a callback channel on an IPv6 socket.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/nfsd/nfs4state.c |   88 +++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 78 insertions(+), 10 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f1caddd..6c6799d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -55,6 +55,8 @@
 #include <linux/lockd/bind.h>
 #include <linux/module.h>
 #include <linux/sunrpc/svcauth_gss.h>
+#include <linux/inet.h>
+#include <net/ipv6.h>
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
@@ -73,6 +75,12 @@ static u64 current_sessionid = 1;
 #define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))
 #define ONE_STATEID(stateid)  (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#define ADDR_STRLEN INET6_ADDRSTRLEN
+#else /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+#define ADDR_STRLEN INET_ADDRSTRLEN
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+
 /* forward declarations */
 static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
 static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
@@ -983,19 +991,58 @@ parse_ipv4(unsigned int addrlen, char *addr, struct sockaddr_in *s4)
 	return parse_port(addrlen, addr, &s4->sin_port);
 }
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int
+parse_ipv6(unsigned int addrlen, char *addr, struct sockaddr_in6 *s6)
+{
+	char *dot;
+
+	s6->sin6_family = AF_INET6;
+
+	if (!in6_pton(addr, addrlen, (u8 *) &s6->sin6_addr.s6_addr, '.',
+		      (const char **) &dot))
+		return 0;
+
+	if ((addr + addrlen) <= dot)
+		return 0;
+
+	if (*dot++ != '.')
+		return 0;
+
+	return parse_port(addrlen - (dot - addr), dot, &s6->sin6_port);
+}
+#else /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+static int
+parse_ipv6(unsigned int addrlen, char *addr, struct sockaddr_in6 *s6)
+{
+	return 0;
+}
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+
 static void
 gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
 {
 	struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
 
-	/* Currently, we only support tcp for the callback channel */
-	if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3))
+	/* Currently, we only support tcp and tcp6 for the callback channel */
+	if (se->se_callback_netid_len == 3 &&
+	    !memcmp(se->se_callback_netid_val, "tcp", 3)) {
+		if (!parse_ipv4(se->se_callback_addr_len,
+				se->se_callback_addr_val,
+				(struct sockaddr_in *) &cb->cb_addr))
+			goto out_err;
+		cb->cb_addrlen = sizeof(struct sockaddr_in);
+	} else if (se->se_callback_netid_len == 4 &&
+		   !memcmp(se->se_callback_netid_val, "tcp6", 4)) {
+		if (!parse_ipv6(se->se_callback_addr_len,
+				se->se_callback_addr_val,
+				(struct sockaddr_in6 *) &cb->cb_addr))
+			goto out_err;
+		cb->cb_addrlen = sizeof(struct sockaddr_in6);
+	} else {
 		goto out_err;
+	}
 
-	if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val,
-			  (struct sockaddr_in *) &cb->cb_addr)))
-		goto out_err;
-	cb->cb_addrlen = sizeof(struct sockaddr_in);
 	cb->cb_prog = se->se_callback_prog;
 	cb->cb_ident = se->se_callback_ident;
 	return;
@@ -1203,6 +1250,7 @@ static bool
 cl_addr_equal(struct sockaddr *a, struct sockaddr *b)
 {
 	struct sockaddr_in *a4, *b4;
+	struct sockaddr_in6 *a6, *b6;
 
 	if (a->sa_family != b->sa_family)
 		return false;
@@ -1212,6 +1260,12 @@ cl_addr_equal(struct sockaddr *a, struct sockaddr *b)
 		a4 = (struct sockaddr_in *) a;
 		b4 = (struct sockaddr_in *) b;
 		return (a4->sin_addr.s_addr == b4->sin_addr.s_addr);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	case AF_INET6:
+		a6 = (struct sockaddr_in6 *) a;
+		b6 = (struct sockaddr_in6 *) b;
+		return ipv6_addr_equal(&a6->sin6_addr, &b6->sin6_addr);
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
 	}
 
 	/* not sure how to compare, so just return false */
@@ -1223,6 +1277,7 @@ static void
 cl_addr_copy(struct sockaddr *dst, struct sockaddr *src)
 {
 	struct sockaddr_in *s4, *d4;
+	struct sockaddr_in6 *s6, *d6;
 
 	dst->sa_family = src->sa_family;
 
@@ -1232,6 +1287,13 @@ cl_addr_copy(struct sockaddr *dst, struct sockaddr *src)
 		d4 = (struct sockaddr_in *) dst;
 		d4->sin_addr.s_addr = s4->sin_addr.s_addr;
 		return;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	case AF_INET6:
+		s6 = (struct sockaddr_in6 *) src;
+		d6 = (struct sockaddr_in6 *) dst;
+		ipv6_addr_copy(&d6->sin6_addr, &s6->sin6_addr);
+		return;
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
 	default:
 		dst->sa_family = AF_UNSPEC;
 	}
@@ -1246,6 +1308,12 @@ cl_addr_snprintf(char *buf, size_t size, struct sockaddr *sa)
 		snprintf(buf, size, "%pI4",
 			 &((struct sockaddr_in *) sa)->sin_addr.s_addr);
 		break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	case AF_INET6:
+		snprintf(buf, size, "%pI6",
+			 &((struct sockaddr_in6 *) sa)->sin6_addr.s6_addr);
+		break;
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
 	default:
 		snprintf(buf, size, "(family=%hu)", sa->sa_family);
 	}
@@ -1263,11 +1331,11 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 	int status;
 	unsigned int		strhashval;
 	char			dname[HEXDIR_LEN];
-	char			addr_str[INET_ADDRSTRLEN];
+	char			addr_str[ADDR_STRLEN];
 	nfs4_verifier		verf = exid->verifier;
 	struct sockaddr		*sa = svc_addr(rqstp);
 
-	cl_addr_snprintf(addr_str, INET_ADDRSTRLEN, sa);
+	cl_addr_snprintf(addr_str, ADDR_STRLEN, sa);
 	dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
 		"ip_addr=%s flags %x, spa_how %d\n",
 		__func__, rqstp, exid, exid->clname.len, exid->clname.data,
@@ -1631,8 +1699,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		/* RFC 3530 14.2.33 CASE 0: */
 		status = nfserr_clid_inuse;
 		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
-			char addr_str[INET_ADDRSTRLEN];
-			cl_addr_snprintf(addr_str, INET_ADDRSTRLEN,
+			char addr_str[ADDR_STRLEN];
+			cl_addr_snprintf(addr_str, ADDR_STRLEN,
 					 (struct sockaddr *) &conf->cl_addr);
 			dprintk("NFSD: setclientid: string in use by client "
 				"at %s\n", addr_str);
-- 
1.6.0.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/4] nfsd: add support for NFSv4 callbacks over IPv6
  2009-06-17 18:15 [PATCH 0/4] nfsd: add support for NFSv4 callbacks over IPv6 Jeff Layton
                   ` (3 preceding siblings ...)
  2009-06-17 18:15 ` [PATCH 4/4] nfsd: add support for NFSv4 callbacks over IPv6 Jeff Layton
@ 2009-06-17 18:47 ` J. Bruce Fields
  2009-06-17 19:01   ` Jeff Layton
  4 siblings, 1 reply; 7+ messages in thread
From: J. Bruce Fields @ 2009-06-17 18:47 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-nfs, chuck.lever

On Wed, Jun 17, 2009 at 02:15:37PM -0400, Jeff Layton wrote:
> This patchset is a first pass at adding IPv6 callback channel support
> for knfsd. The set is fairly straightforward, but it does require a
> number of changes to server side NFSv4 related structs that store
> addresses in places that are only suitable for IPv4 addresses.
> 
> I've tested this by having Linux and OpenSolaris clients mount the
> server over an IPv6 socket, get a delegation and ensure that the server
> can recall that delegation. It all seems to work as expected. IPv4
> callbacks also seem to continue to work correctly.
> 
> This patchset does change the some of the new 4.1 functions
> (nfsd4_exchange_id in particular). Those changes are untested as of yet
> but I'll see if I can do so if the approach in this set seems
> reasonable.

Thanks, just two quick comments:

	1. I've been working on the callback code, so check that this
	applies against for-2.6.31 (at
	git://linux-nfs.org/~bfields/linux.git).
	2. Any IP address checks in setclientid or exchange_id are
	probably bogus; the former should be gone, the latter may still
	be there but there'll be a patch queued up for 2.6.31 to fix
	that.

--b.

> 
> Comments welcome...
> 
> Jeff Layton (4):
>   nfsd: convert nfs4_callback struct to hold address in
>     sockaddr_storage
>   nfsd: break out setclientid port parsing into separate routine
>   nfsd: make nfs4_client->cl_addr a struct sockaddr_storage
>   nfsd: add support for NFSv4 callbacks over IPv6
> 
>  fs/nfsd/nfs4callback.c     |   11 +--
>  fs/nfsd/nfs4state.c        |  220 ++++++++++++++++++++++++++++++++++++-------
>  include/linux/nfsd/state.h |    6 +-
>  3 files changed, 189 insertions(+), 48 deletions(-)
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/4] nfsd: add support for NFSv4 callbacks over IPv6
  2009-06-17 18:47 ` [PATCH 0/4] " J. Bruce Fields
@ 2009-06-17 19:01   ` Jeff Layton
  0 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2009-06-17 19:01 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: linux-nfs, chuck.lever

On Wed, 17 Jun 2009 14:47:01 -0400
"J. Bruce Fields" <bfields@fieldses.org> wrote:

> On Wed, Jun 17, 2009 at 02:15:37PM -0400, Jeff Layton wrote:
> > This patchset is a first pass at adding IPv6 callback channel support
> > for knfsd. The set is fairly straightforward, but it does require a
> > number of changes to server side NFSv4 related structs that store
> > addresses in places that are only suitable for IPv4 addresses.
> > 
> > I've tested this by having Linux and OpenSolaris clients mount the
> > server over an IPv6 socket, get a delegation and ensure that the server
> > can recall that delegation. It all seems to work as expected. IPv4
> > callbacks also seem to continue to work correctly.
> > 
> > This patchset does change the some of the new 4.1 functions
> > (nfsd4_exchange_id in particular). Those changes are untested as of yet
> > but I'll see if I can do so if the approach in this set seems
> > reasonable.
> 
> Thanks, just two quick comments:
> 
> 	1. I've been working on the callback code, so check that this
> 	applies against for-2.6.31 (at
> 	git://linux-nfs.org/~bfields/linux.git).

Sorry, I should have made it clear in the original email. This patchset
applies cleanly to your master branch. I just checked and it also
applies cleanly to your for-2.6.31 branch.

> 	2. Any IP address checks in setclientid or exchange_id are
> 	probably bogus; the former should be gone, the latter may still
> 	be there but there'll be a patch queued up for 2.6.31 to fix
> 	that.
> 

There are definitely still IP address comparisons in those functions,
though I confess I didn't look closely at the logic. My main concern
with this set was to move the IPv4 specific address containers to
sockaddr_storage, and to make the comparisons work for alternate
address families. I tried not to alter the logic however.

Thanks,
-- 
Jeff Layton <jlayton@redhat.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2009-06-17 19:01 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-17 18:15 [PATCH 0/4] nfsd: add support for NFSv4 callbacks over IPv6 Jeff Layton
2009-06-17 18:15 ` [PATCH 1/4] nfsd: convert nfs4_callback struct to hold address in sockaddr_storage Jeff Layton
2009-06-17 18:15 ` [PATCH 2/4] nfsd: break out setclientid port parsing into separate routine Jeff Layton
2009-06-17 18:15 ` [PATCH 3/4] nfsd: make nfs4_client->cl_addr a struct sockaddr_storage Jeff Layton
2009-06-17 18:15 ` [PATCH 4/4] nfsd: add support for NFSv4 callbacks over IPv6 Jeff Layton
2009-06-17 18:47 ` [PATCH 0/4] " J. Bruce Fields
2009-06-17 19:01   ` Jeff Layton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.