* [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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ messages in thread