* [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses
@ 2007-08-09 7:22 Aurélien Charbon
2007-08-09 12:16 ` Chuck Lever
2007-08-10 1:06 ` Neil Brown
0 siblings, 2 replies; 11+ messages in thread
From: Aurélien Charbon @ 2007-08-09 7:22 UTC (permalink / raw)
To: Mailing list NFSv4; +Cc: netdev ML
Here is a small part of missing pieces of IPv6 support for the server.
It deals with the ip_map caching code part.
It changes the ip_map structure to be able to store INET6 addresses.
It adds also the changes in address hashing, and mapping to test it with
INET addresses.
Signed-off-by: Aurelien Charbon <aurelien.charbon@ext.bull.net>
---
fs/nfsd/export.c | 12 ++++-
fs/nfsd/nfsctl.c | 21 ++++++++-
include/linux/sunrpc/svcauth.h | 4 -
net/sunrpc/svcauth_unix.c | 90
++++++++++++++++++++++++++---------------
4 files changed, 87 insertions(+), 40 deletions(-)
diff -u -r -N linux-2.6.23-rc1/fs/nfsd/export.c
linux-2.6.23-rc1-IPv6-ip_map/fs/nfsd/export.c
--- linux-2.6.23-rc1/fs/nfsd/export.c 2007-08-08 17:52:58.000000000 +0200
+++ linux-2.6.23-rc1-IPv6-ip_map/fs/nfsd/export.c 2007-08-08
17:49:09.000000000 +0200
@@ -1558,6 +1558,7 @@
{
struct auth_domain *dom;
int i, err;
+ struct in6_addr addr6;
/* First, consistency check. */
err = -EINVAL;
@@ -1576,9 +1577,14 @@
goto out_unlock;
/* Insert client into hashtable. */
- for (i = 0; i < ncp->cl_naddr; i++)
- auth_unix_add_addr(ncp->cl_addrlist[i], dom);
-
+ for (i = 0; i < ncp->cl_naddr; i++) {
+ /* Mapping address */
+ addr6.s6_addr32[0] = 0;
+ addr6.s6_addr32[1] = 0;
+ addr6.s6_addr32[2] = htonl(0xffff);
+ addr6.s6_addr32[3] = (uint32_t)ncp->cl_addrlist[i].s_addr;
+ auth_unix_add_addr(addr6, dom);
+ }
auth_unix_forget_old(dom);
auth_domain_put(dom);
diff -u -r -N linux-2.6.23-rc1/fs/nfsd/nfsctl.c
linux-2.6.23-rc1-IPv6-ip_map/fs/nfsd/nfsctl.c
--- linux-2.6.23-rc1/fs/nfsd/nfsctl.c 2007-08-08 17:52:58.000000000 +0200
+++ linux-2.6.23-rc1-IPv6-ip_map/fs/nfsd/nfsctl.c 2007-08-08
17:49:09.000000000 +0200
@@ -222,7 +222,7 @@
struct auth_domain *clp;
int err = 0;
struct knfsd_fh *res;
-
+ struct in6_addr in6;
if (size < sizeof(*data))
return -EINVAL;
data = (struct nfsctl_fsparm*)buf;
@@ -236,7 +236,14 @@
res = (struct knfsd_fh*)buf;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ in6.s6_addr32[0] = 0;
+ in6.s6_addr32[1] = 0;
+ in6.s6_addr32[2] = htonl(0xffff);
+ in6.s6_addr32[3] = (uint32_t)sin->sin_addr.s_addr;
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -253,6 +260,7 @@
{
struct nfsctl_fdparm *data;
struct sockaddr_in *sin;
+ struct in6_addr in6;
struct auth_domain *clp;
int err = 0;
struct knfsd_fh fh;
@@ -271,7 +279,14 @@
res = buf;
sin = (struct sockaddr_in *)&data->gd_addr;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ in6.s6_addr32[0] = 0;
+ in6.s6_addr32[1] = 0;
+ in6.s6_addr32[2] = htonl(0xffff);
+ in6.s6_addr32[3] = (uint32_t)sin->sin_addr.s_addr;
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
diff -u -r -N linux-2.6.23-rc1/include/linux/sunrpc/svcauth.h
linux-2.6.23-rc1-IPv6-ip_map/include/linux/sunrpc/svcauth.h
--- linux-2.6.23-rc1/include/linux/sunrpc/svcauth.h 2007-08-08
17:52:59.000000000 +0200
+++ linux-2.6.23-rc1-IPv6-ip_map/include/linux/sunrpc/svcauth.h
2007-08-08 17:48:54.000000000 +0200
@@ -120,10 +120,10 @@
extern struct auth_domain *unix_domain_find(char *name);
extern void auth_domain_put(struct auth_domain *item);
-extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain
*dom);
+extern int auth_unix_add_addr(struct in6_addr addr, struct auth_domain
*dom);
extern struct auth_domain *auth_domain_lookup(char *name, struct
auth_domain *new);
extern struct auth_domain *auth_domain_find(char *name);
-extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
+extern struct auth_domain *auth_unix_lookup(struct in6_addr addr);
extern int auth_unix_forget_old(struct auth_domain *dom);
extern void svcauth_unix_purge(void);
extern void svcauth_unix_info_release(void *);
diff -u -r -N linux-2.6.23-rc1/net/sunrpc/svcauth_unix.c
linux-2.6.23-rc1-IPv6-ip_map/net/sunrpc/svcauth_unix.c
--- linux-2.6.23-rc1/net/sunrpc/svcauth_unix.c 2007-08-08
17:53:01.000000000 +0200
+++ linux-2.6.23-rc1-IPv6-ip_map/net/sunrpc/svcauth_unix.c 2007-08-09
08:29:27.000000000 +0200
@@ -84,7 +84,7 @@
struct ip_map {
struct cache_head h;
char m_class[8]; /* e.g. "nfsd" */
- struct in_addr m_addr;
+ struct in6_addr m_addr;
struct unix_domain *m_client;
int m_add_change;
};
@@ -112,12 +112,16 @@
return (hash ^ (hash>>8)) & 0xff;
}
#endif
+static inline int hash_ip6(struct in6_addr ip)
+{
+ return (hash_ip(ip.s6_addr32[0]) ^ hash_ip(ip.s6_addr32[1]) ^
hash_ip(ip.s6_addr32[2]) ^ hash_ip(ip.s6_addr32[3])) ;
+}
static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
{
struct ip_map *orig = container_of(corig, struct ip_map, h);
struct ip_map *new = container_of(cnew, struct ip_map, h);
return strcmp(orig->m_class, new->m_class) == 0
- && orig->m_addr.s_addr == new->m_addr.s_addr;
+ && memcmp(orig->m_addr.s6_addr,
new->m_addr.s6_addr,sizeof(struct in6_addr));
}
static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
{
@@ -125,7 +129,7 @@
struct ip_map *item = container_of(citem, struct ip_map, h);
strcpy(new->m_class, item->m_class);
- new->m_addr.s_addr = item->m_addr.s_addr;
+ memcpy(&new->m_addr.s6_addr,
&item->m_addr.s6_addr,sizeof(item->m_addr.s6_addr));
}
static void update(struct cache_head *cnew, struct cache_head *citem)
{
@@ -151,20 +155,28 @@
{
char text_addr[20];
struct ip_map *im = container_of(h, struct ip_map, h);
- __be32 addr = im->m_addr.s_addr;
+
+ __be32 addr[4];
+ int i;
+ for (i=0;i<4;i++)
+ addr[i] = im->m_addr.s6_addr[i];
- snprintf(text_addr, 20, "%u.%u.%u.%u",
- ntohl(addr) >> 24 & 0xff,
- ntohl(addr) >> 16 & 0xff,
- ntohl(addr) >> 8 & 0xff,
- ntohl(addr) >> 0 & 0xff);
+ snprintf(text_addr, 20, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+ ntohl(addr[3]) >> 16 & 0xff,
+ ntohl(addr[3]) >> 0 & 0xff,
+ ntohl(addr[2]) >> 16 & 0xff,
+ ntohl(addr[2]) >> 0 & 0xff,
+ ntohl(addr[1]) >> 16 & 0xff,
+ ntohl(addr[1]) >> 0 & 0xff,
+ ntohl(addr[0]) >> 16 & 0xff,
+ ntohl(addr[0]) >> 0 & 0xff);
qword_add(bpp, blen, im->m_class);
qword_add(bpp, blen, text_addr);
(*bpp)[-1] = '\n';
}
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr addr);
static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom,
time_t expiry);
static int ip_map_parse(struct cache_detail *cd,
@@ -175,10 +187,10 @@
* for scratch: */
char *buf = mesg;
int len;
- int b1,b2,b3,b4;
+ int b1,b2,b3,b4,b5,b6,b7,b8;
char c;
char class[8];
- struct in_addr addr;
+ struct in6_addr addr;
int err;
struct ip_map *ipmp;
@@ -197,8 +209,21 @@
len = qword_get(&mesg, buf, mlen);
if (len <= 0) return -EINVAL;
- if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
- return -EINVAL;
+ if (sscanf(buf, "%d.%d.%d.%d%c", &b1, &b2, &b3, &b4, &c) == 4) {
+ addr.s6_addr32[0] = 0;
+ addr.s6_addr32[1] = 0;
+ addr.s6_addr32[2] = htonl(0xffff);
+ addr.s6_addr32[3] =
+ htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
+ } else if (sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x%c",
+ &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) ==
8) {
+ addr.s6_addr32[0] = htonl((b1<<16)|b2);
+ addr.s6_addr32[1] = htonl((b3<<16)|b4);
+ addr.s6_addr32[2] = htonl((b5<<16)|b6);
+ addr.s6_addr32[3] = htonl((b7<<16)|b8);
+ } else
+ return -EINVAL;
+
expiry = get_expiry(&mesg);
if (expiry ==0)
@@ -215,9 +240,6 @@
} else
dom = NULL;
- addr.s_addr =
- htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
-
ipmp = ip_map_lookup(class,addr);
if (ipmp) {
err = ip_map_update(ipmp,
@@ -238,7 +260,7 @@
struct cache_head *h)
{
struct ip_map *im;
- struct in_addr addr;
+ struct in6_addr addr;
char *dom = "-no-domain-";
if (h == NULL) {
@@ -247,18 +269,22 @@
}
im = container_of(h, struct ip_map, h);
/* class addr domain */
- addr = im->m_addr;
+ memcpy(&addr, &im->m_addr, sizeof(struct in6_addr));
if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags))
dom = im->m_client->h.name;
- seq_printf(m, "%s %d.%d.%d.%d %s\n",
+ seq_printf(m, "%s %04x.%04x.%04x.%04x.%04x.%04x.%04x.%04x %s\n",
im->m_class,
- ntohl(addr.s_addr) >> 24 & 0xff,
- ntohl(addr.s_addr) >> 16 & 0xff,
- ntohl(addr.s_addr) >> 8 & 0xff,
- ntohl(addr.s_addr) >> 0 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 16 & 0xffff,
+ ntohl(addr.s6_addr32[3]) & 0xffff,
+ ntohl(addr.s6_addr32[2]) >> 16 & 0xffff,
+ ntohl(addr.s6_addr32[2]) & 0xffff,
+ ntohl(addr.s6_addr32[1]) >> 16 & 0xffff,
+ ntohl(addr.s6_addr32[1]) & 0xffff,
+ ntohl(addr.s6_addr32[0]) >> 16 & 0xffff,
+ ntohl(addr.s6_addr32[0]) & 0xffff,
dom
);
return 0;
@@ -280,16 +306,16 @@
.alloc = ip_map_alloc,
};
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr addr)
{
struct ip_map ip;
struct cache_head *ch;
strcpy(ip.m_class, class);
- ip.m_addr = addr;
+ memcpy(&ip.m_addr, &addr, sizeof(struct in6_addr));
ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
hash_str(class, IP_HASHBITS) ^
- hash_ip(addr.s_addr));
+ hash_ip6(addr));
if (ch)
return container_of(ch, struct ip_map, h);
@@ -318,14 +344,14 @@
ch = sunrpc_cache_update(&ip_map_cache,
&ip.h, &ipm->h,
hash_str(ipm->m_class, IP_HASHBITS) ^
- hash_ip(ipm->m_addr.s_addr));
+ hash_ip6(ipm->m_addr));
if (!ch)
return -ENOMEM;
cache_put(ch, &ip_map_cache);
return 0;
}
-int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
+int auth_unix_add_addr(struct in6_addr addr, struct auth_domain *dom)
{
struct unix_domain *udom;
struct ip_map *ipmp;
@@ -352,7 +378,7 @@
return 0;
}
-struct auth_domain *auth_unix_lookup(struct in_addr addr)
+struct auth_domain *auth_unix_lookup(struct in6_addr addr)
{
struct ip_map *ipm;
struct auth_domain *rv;
@@ -641,7 +667,7 @@
int
svcauth_unix_set_client(struct svc_rqst *rqstp)
{
- struct sockaddr_in *sin = svc_addr_in(rqstp);
+ struct sockaddr_in6 *sin = svc_addr_in6(rqstp);
struct ip_map *ipm;
rqstp->rq_client = NULL;
@@ -651,7 +677,7 @@
ipm = ip_map_cached_get(rqstp);
if (ipm == NULL)
ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
- sin->sin_addr);
+ sin->sin6_addr);
if (ipm == NULL)
return SVC_DENIED;
--
********************************
Aurelien Charbon
Linux NFSv4 team
Bull SAS
Echirolles - France
http://nfsv4.bullopensource.org/
********************************
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses
2007-08-09 7:22 [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses Aurélien Charbon
@ 2007-08-09 12:16 ` Chuck Lever
2007-08-09 15:08 ` Aurélien Charbon
2007-08-10 1:06 ` Neil Brown
1 sibling, 1 reply; 11+ messages in thread
From: Chuck Lever @ 2007-08-09 12:16 UTC (permalink / raw)
To: Aurélien Charbon; +Cc: Mailing list NFSv4, netdev ML, Neil Brown
[-- Attachment #1: Type: text/plain, Size: 6312 bytes --]
Aurélien Charbon wrote:
> Here is a small part of missing pieces of IPv6 support for the server.
> It deals with the ip_map caching code part.
>
> It changes the ip_map structure to be able to store INET6 addresses.
> It adds also the changes in address hashing, and mapping to test it with
> INET addresses.
Thanks for posting your patch.
Your strategy is to convert all incoming IPv4 addresses in the ip_map
cache to IPv6 addresses, and use only IPv6 internally (often suggested
by IPv6 books I've encountered). For NFS, that is problematic because
these addresses are used as the target of access control rules for
exports; thus sys admins will expect to see IPv4 addresses in the output
of NFS utilities if they specified IPv4 addresses in their /etc/exports
file, for example.
Some naive questions:
1. If IPv6 support is not configured into the kernel, how does an
IPv6-only cache work?
2. I seem to recall (only quite vaguely) that at some point the server
might need to use one of the stored addresses to, say, open a socket to
the client? In that case, on a system with NICs configured only with
IPv4, is the cached IPv6 address properly converted back to IPv4
somehow? Can the cache code tell the difference between a cached IPv6
address that was converted from IPv4 and one that was added to the cache
as IPv6? Sorry I can't remember more clearly.
3. Would it be better to make the m_addr field a struct sockaddr, store
a whole address (with address family), and switch on the sa_family field?
> diff -u -r -N linux-2.6.23-rc1/fs/nfsd/export.c
> linux-2.6.23-rc1-IPv6-ip_map/fs/nfsd/export.c
> --- linux-2.6.23-rc1/fs/nfsd/export.c 2007-08-08 17:52:58.000000000 +0200
> +++ linux-2.6.23-rc1-IPv6-ip_map/fs/nfsd/export.c 2007-08-08
> 17:49:09.000000000 +0200
> @@ -1558,6 +1558,7 @@
> {
> struct auth_domain *dom;
> int i, err;
> + struct in6_addr addr6;
>
> /* First, consistency check. */
> err = -EINVAL;
> @@ -1576,9 +1577,14 @@
> goto out_unlock;
>
> /* Insert client into hashtable. */
> - for (i = 0; i < ncp->cl_naddr; i++)
> - auth_unix_add_addr(ncp->cl_addrlist[i], dom);
> -
> + for (i = 0; i < ncp->cl_naddr; i++) {
> + /* Mapping address */
> + addr6.s6_addr32[0] = 0;
> + addr6.s6_addr32[1] = 0;
> + addr6.s6_addr32[2] = htonl(0xffff);
> + addr6.s6_addr32[3] = (uint32_t)ncp->cl_addrlist[i].s_addr;
> + auth_unix_add_addr(addr6, dom);
> + }
> auth_unix_forget_old(dom);
> auth_domain_put(dom);
This converts IPv4 addresses to canonical IPv6 as it stores them. What
happens if a full-blown IPv6 address is encountered? Likewise, in nfsctl.c?
> @@ -112,12 +112,16 @@
> return (hash ^ (hash>>8)) & 0xff;
> }
> #endif
> +static inline int hash_ip6(struct in6_addr ip)
> +{
> + return (hash_ip(ip.s6_addr32[0]) ^ hash_ip(ip.s6_addr32[1]) ^
> hash_ip(ip.s6_addr32[2]) ^ hash_ip(ip.s6_addr32[3])) ;
> +}
How have you tested the effectiveness of the new hash function?
> @@ -151,20 +155,28 @@
> {
> char text_addr[20];
> struct ip_map *im = container_of(h, struct ip_map, h);
> - __be32 addr = im->m_addr.s_addr;
> +
> + __be32 addr[4];
> + int i;
> + for (i=0;i<4;i++)
> + addr[i] = im->m_addr.s6_addr[i];
>
> - snprintf(text_addr, 20, "%u.%u.%u.%u",
> - ntohl(addr) >> 24 & 0xff,
> - ntohl(addr) >> 16 & 0xff,
> - ntohl(addr) >> 8 & 0xff,
> - ntohl(addr) >> 0 & 0xff);
> + snprintf(text_addr, 20, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
> + ntohl(addr[3]) >> 16 & 0xff,
> + ntohl(addr[3]) >> 0 & 0xff,
> + ntohl(addr[2]) >> 16 & 0xff,
> + ntohl(addr[2]) >> 0 & 0xff,
> + ntohl(addr[1]) >> 16 & 0xff,
> + ntohl(addr[1]) >> 0 & 0xff,
> + ntohl(addr[0]) >> 16 & 0xff,
> + ntohl(addr[0]) >> 0 & 0xff);
The snprintf() format strings should use NIP6_FMT.
> @@ -197,8 +209,21 @@
> len = qword_get(&mesg, buf, mlen);
> if (len <= 0) return -EINVAL;
>
> - if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
> - return -EINVAL;
> + if (sscanf(buf, "%d.%d.%d.%d%c", &b1, &b2, &b3, &b4, &c) == 4) {
> + addr.s6_addr32[0] = 0;
> + addr.s6_addr32[1] = 0;
> + addr.s6_addr32[2] = htonl(0xffff);
> + addr.s6_addr32[3] =
> + htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
> + } else if (sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x%c",
> + &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) ==
> 8) {
> + addr.s6_addr32[0] = htonl((b1<<16)|b2);
> + addr.s6_addr32[1] = htonl((b3<<16)|b4);
> + addr.s6_addr32[2] = htonl((b5<<16)|b6);
> + addr.s6_addr32[3] = htonl((b7<<16)|b8);
> + } else
> + return -EINVAL;
> +
Likewise, the sscanf() format strings should use NIP6_FMT.
> @@ -247,18 +269,22 @@
> }
> im = container_of(h, struct ip_map, h);
> /* class addr domain */
> - addr = im->m_addr;
> + memcpy(&addr, &im->m_addr, sizeof(struct in6_addr));
>
> if (test_bit(CACHE_VALID, &h->flags) &&
> !test_bit(CACHE_NEGATIVE, &h->flags))
> dom = im->m_client->h.name;
>
> - seq_printf(m, "%s %d.%d.%d.%d %s\n",
> + seq_printf(m, "%s %04x.%04x.%04x.%04x.%04x.%04x.%04x.%04x %s\n",
> im->m_class,
> - ntohl(addr.s_addr) >> 24 & 0xff,
> - ntohl(addr.s_addr) >> 16 & 0xff,
> - ntohl(addr.s_addr) >> 8 & 0xff,
> - ntohl(addr.s_addr) >> 0 & 0xff,
> + ntohl(addr.s6_addr32[3]) >> 16 & 0xffff,
> + ntohl(addr.s6_addr32[3]) & 0xffff,
> + ntohl(addr.s6_addr32[2]) >> 16 & 0xffff,
> + ntohl(addr.s6_addr32[2]) & 0xffff,
> + ntohl(addr.s6_addr32[1]) >> 16 & 0xffff,
> + ntohl(addr.s6_addr32[1]) & 0xffff,
> + ntohl(addr.s6_addr32[0]) >> 16 & 0xffff,
> + ntohl(addr.s6_addr32[0]) & 0xffff,
> dom
> );
> return 0;
And I think here NIP6_FMT should be used, but you're not using colons
between the hex digits. Was that intentional?
[-- Attachment #2: chuck.lever.vcf --]
[-- Type: text/x-vcard, Size: 302 bytes --]
begin:vcard
fn:Chuck Lever
n:Lever;Chuck
org:Oracle Corporation;Corporate Architecture: Linux Projects Group
adr:;;1015 Granger Avenue;Ann Arbor;MI;48104;USA
title:Principal Member of Staff
tel;work:+1 248 614 5091
x-mozilla-html:FALSE
url:http://oss.oracle.com/~cel
version:2.1
end:vcard
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses
2007-08-09 12:16 ` Chuck Lever
@ 2007-08-09 15:08 ` Aurélien Charbon
2007-08-09 15:14 ` Chuck Lever
0 siblings, 1 reply; 11+ messages in thread
From: Aurélien Charbon @ 2007-08-09 15:08 UTC (permalink / raw)
To: chuck.lever; +Cc: Mailing list NFSv4, netdev ML, Neil Brown
Thanks for these comments.
Chuck Lever wrote:
> Some naive questions:
>
> 1. If IPv6 support is not configured into the kernel, how does an
> IPv6-only cache work?
Yes it should work.
The INET6 structures are only used as containers for both type of address.
I have tested by unabling IPv6 options in the .config file.
>
> 2. I seem to recall (only quite vaguely) that at some point the
> server might need to use one of the stored addresses to, say, open a
> socket to the client? In that case, on a system with NICs configured
> only with IPv4, is the cached IPv6 address properly converted back to
> IPv4 somehow?
Yes. we can do that by testing the format of the address, as we know
that an IPv4 address is mapped like that:
[00000000] [00000000] [0000FFFF] <32 bits of IPv4 addr>
> Can the cache code tell the difference between a cached IPv6 address
> that was converted from IPv4 and one that was added to the cache as
> IPv6? Sorry I can't remember more clearly.
Yes. If the address starts with ::FFFF, we can infer that is a mapped
IPv4 address.
>
> 3. Would it be better to make the m_addr field a struct sockaddr,
> store a whole address (with address family), and switch on the
> sa_family field?
That is possible but we're able to retrieve the family of the address by
testing its format (IPv4 mapped or not).
But I don't know if it is a better solution.
>
>
>> diff -u -r -N linux-2.6.23-rc1/fs/nfsd/export.c
>> linux-2.6.23-rc1-IPv6-ip_map/fs/nfsd/export.c
>> --- linux-2.6.23-rc1/fs/nfsd/export.c 2007-08-08
>> 17:52:58.000000000 +0200
>> +++ linux-2.6.23-rc1-IPv6-ip_map/fs/nfsd/export.c 2007-08-08
>> 17:49:09.000000000 +0200
>> @@ -1558,6 +1558,7 @@
>> {
>> struct auth_domain *dom;
>> int i, err;
>> + struct in6_addr addr6;
>>
>> /* First, consistency check. */
>> err = -EINVAL;
>> @@ -1576,9 +1577,14 @@
>> goto out_unlock;
>>
>> /* Insert client into hashtable. */
>> - for (i = 0; i < ncp->cl_naddr; i++)
>> - auth_unix_add_addr(ncp->cl_addrlist[i], dom);
>> -
>> + for (i = 0; i < ncp->cl_naddr; i++) {
>> + /* Mapping address */
>> + addr6.s6_addr32[0] = 0;
>> + addr6.s6_addr32[1] = 0;
>> + addr6.s6_addr32[2] = htonl(0xffff);
>> + addr6.s6_addr32[3] = (uint32_t)ncp->cl_addrlist[i].s_addr;
>> + auth_unix_add_addr(addr6, dom);
>> + }
>> auth_unix_forget_old(dom);
>> auth_domain_put(dom);
>
>
> This converts IPv4 addresses to canonical IPv6 as it stores them.
> What happens if a full-blown IPv6 address is encountered? Likewise,
> in nfsctl.c?
I have done this kind of convertion only for compilation an testing with
only IPv4... For the moment.
>
>> @@ -112,12 +112,16 @@
>> return (hash ^ (hash>>8)) & 0xff;
>> }
>> #endif
>> +static inline int hash_ip6(struct in6_addr ip)
>> +{
>> + return (hash_ip(ip.s6_addr32[0]) ^ hash_ip(ip.s6_addr32[1])
>> ^ hash_ip(ip.s6_addr32[2]) ^ hash_ip(ip.s6_addr32[3])) ;
>> +}
>
>
> How have you tested the effectiveness of the new hash function?
I have not tested that point but I can easily imagine there are better
solutions.
Perhaps we can keep the same function for an IPv4 address (only taking
the 32 bits of IPv4 addr), and then design one for IPv6 addresses.
Do you have any suggestion on that ?
>> - seq_printf(m, "%s %d.%d.%d.%d %s\n",
>> + seq_printf(m, "%s %04x.%04x.%04x.%04x.%04x.%04x.%04x.%04x %s\n",
>> im->m_class,
>> - ntohl(addr.s_addr) >> 24 & 0xff,
>> - ntohl(addr.s_addr) >> 16 & 0xff,
>> - ntohl(addr.s_addr) >> 8 & 0xff,
>> - ntohl(addr.s_addr) >> 0 & 0xff,
>> + ntohl(addr.s6_addr32[3]) >> 16 & 0xffff,
>> + ntohl(addr.s6_addr32[3]) & 0xffff,
>> + ntohl(addr.s6_addr32[2]) >> 16 & 0xffff,
>> + ntohl(addr.s6_addr32[2]) & 0xffff,
>> + ntohl(addr.s6_addr32[1]) >> 16 & 0xffff,
>> + ntohl(addr.s6_addr32[1]) & 0xffff,
>> + ntohl(addr.s6_addr32[0]) >> 16 & 0xffff,
>> + ntohl(addr.s6_addr32[0]) & 0xffff,
>> dom
>> );
>> return 0;
>
>
> And I think here NIP6_FMT should be used, but you're not using colons
> between the hex digits. Was that intentional
> ?
No that's a mistake. Colons have to be used here.
Aurélien
--
********************************
Aurelien Charbon
Linux NFSv4 team
Bull SAS
Echirolles - France
http://nfsv4.bullopensource.org/
********************************
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses
2007-08-09 15:08 ` Aurélien Charbon
@ 2007-08-09 15:14 ` Chuck Lever
2007-08-10 1:11 ` Neil Brown
0 siblings, 1 reply; 11+ messages in thread
From: Chuck Lever @ 2007-08-09 15:14 UTC (permalink / raw)
To: Aurélien Charbon; +Cc: Mailing list NFSv4, netdev ML, Neil Brown
[-- Attachment #1: Type: text/plain, Size: 999 bytes --]
Aurélien Charbon wrote:
>>> @@ -112,12 +112,16 @@
>>> return (hash ^ (hash>>8)) & 0xff;
>>> }
>>> #endif
>>> +static inline int hash_ip6(struct in6_addr ip)
>>> +{
>>> + return (hash_ip(ip.s6_addr32[0]) ^ hash_ip(ip.s6_addr32[1])
>>> ^ hash_ip(ip.s6_addr32[2]) ^ hash_ip(ip.s6_addr32[3])) ;
>>> +}
>>
>>
>> How have you tested the effectiveness of the new hash function?
>
> I have not tested that point but I can easily imagine there are better
> solutions.
> Perhaps we can keep the same function for an IPv4 address (only taking
> the 32 bits of IPv4 addr), and then design one for IPv6 addresses.
I see that, to generate the hash, you would be xor-ing the FF and 00
bytes in the canonicalized IPv4 address. Yes, perhaps a better function
is needed, or as you say, one specifically for IPv6 and one for
canonicalized IPv4.
> Do you have any suggestion on that ?
I don't have anything specific, but you may find something useful if you
poke around elsewhere under net/.
[-- Attachment #2: chuck.lever.vcf --]
[-- Type: text/x-vcard, Size: 302 bytes --]
begin:vcard
fn:Chuck Lever
n:Lever;Chuck
org:Oracle Corporation;Corporate Architecture: Linux Projects Group
adr:;;1015 Granger Avenue;Ann Arbor;MI;48104;USA
title:Principal Member of Staff
tel;work:+1 248 614 5091
x-mozilla-html:FALSE
url:http://oss.oracle.com/~cel
version:2.1
end:vcard
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses
2007-08-09 7:22 [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses Aurélien Charbon
2007-08-09 12:16 ` Chuck Lever
@ 2007-08-10 1:06 ` Neil Brown
1 sibling, 0 replies; 11+ messages in thread
From: Neil Brown @ 2007-08-10 1:06 UTC (permalink / raw)
To: Aurélien Charbon; +Cc: netdev ML, Mailing list NFSv4
On Thursday August 9, aurelien.charbon@ext.bull.net wrote:
> Here is a small part of missing pieces of IPv6 support for the server.
> It deals with the ip_map caching code part.
>
> It changes the ip_map structure to be able to store INET6 addresses.
> It adds also the changes in address hashing, and mapping to test it with
> INET addresses.
Thanks - this generally seems to make sense. A few specific comments:
> @@ -1558,6 +1558,7 @@
Please use "diff -p" to include the C function name. It makes the
patch easier to read.
> + for (i = 0; i < ncp->cl_naddr; i++) {
> + /* Mapping address */
> + addr6.s6_addr32[0] = 0;
> + addr6.s6_addr32[1] = 0;
> + addr6.s6_addr32[2] = htonl(0xffff);
> + addr6.s6_addr32[3] = (uint32_t)ncp->cl_addrlist[i].s_addr;
> + auth_unix_add_addr(addr6, dom);
> + }
You do this conversion several times, and each time it is indented
strangely... Maybe create an inline (if there isn't one already) to
do this.
> extern void auth_domain_put(struct auth_domain *item);
> -extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain
> *dom);
> +extern int auth_unix_add_addr(struct in6_addr addr, struct auth_domain
> *dom);
Your mailer is wrapping long lines. This is bad.
> static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
> {
> struct ip_map *orig = container_of(corig, struct ip_map, h);
> struct ip_map *new = container_of(cnew, struct ip_map, h);
> return strcmp(orig->m_class, new->m_class) == 0
> - && orig->m_addr.s_addr == new->m_addr.s_addr;
> + && memcmp(orig->m_addr.s6_addr,
> new->m_addr.s6_addr,sizeof(struct in6_addr));
> }
I think you have inverted the sense of the test. The original tests
for equality. The new tests for inequality. For memcmp (and strcmp),
always use "function(arg1, argc) COMPARE_OP 0"
e.g.
memcmp(orig, new, size) == 0
or use ipv6_addr_equal.
Also please run ./scripts/checkpatch.pl on the patch. You need a
space after that comma.
> @@ -125,7 +129,7 @@
> struct ip_map *item = container_of(citem, struct ip_map, h);
>
> strcpy(new->m_class, item->m_class);
> - new->m_addr.s_addr = item->m_addr.s_addr;
> + memcpy(&new->m_addr.s6_addr,
> &item->m_addr.s6_addr,sizeof(item->m_addr.s6_addr));
Ditto..... did you test this code?
> }
> static void update(struct cache_head *cnew, struct cache_head *citem)
> {
> @@ -151,20 +155,28 @@
> {
> char text_addr[20];
> struct ip_map *im = container_of(h, struct ip_map, h);
> - __be32 addr = im->m_addr.s_addr;
> +
> + __be32 addr[4];
> + int i;
> + for (i=0;i<4;i++)
> + addr[i] = im->m_addr.s6_addr[i];
^^^^
I think you mean "s6_addr32" ??
>
> - snprintf(text_addr, 20, "%u.%u.%u.%u",
> - ntohl(addr) >> 24 & 0xff,
> - ntohl(addr) >> 16 & 0xff,
> - ntohl(addr) >> 8 & 0xff,
> - ntohl(addr) >> 0 & 0xff);
> + snprintf(text_addr, 20, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
> + ntohl(addr[3]) >> 16 & 0xff,
^^^^
should be 0xffff ???
Now I know you didn't test the code :-)
> + ntohl(addr[3]) >> 0 & 0xff,
> + ntohl(addr[2]) >> 16 & 0xff,
> + ntohl(addr[2]) >> 0 & 0xff,
> + ntohl(addr[1]) >> 16 & 0xff,
> + ntohl(addr[1]) >> 0 & 0xff,
> + ntohl(addr[0]) >> 16 & 0xff,
> + ntohl(addr[0]) >> 0 & 0xff);
This code would read better if you did
__be16 addr[8];
for (i = 0; i < 8 ; i++)
addr[i] = im->m_addr.s6_addr16[i];
snprintf(........
ntohs(addr[7]),
ntohs(addr[6]),
....
Also, I think that if it is a (converted) IPv4 address, it should be
printed as a dotted-quad.
> + addr.s6_addr32[0] = htonl((b1<<16)|b2);
> + addr.s6_addr32[1] = htonl((b3<<16)|b4);
> + addr.s6_addr32[2] = htonl((b5<<16)|b6);
> + addr.s6_addr32[3] = htonl((b7<<16)|b8);
Assign to addr.s6_addr16[].
> - seq_printf(m, "%s %d.%d.%d.%d %s\n",
> + seq_printf(m, "%s %04x.%04x.%04x.%04x.%04x.%04x.%04x.%04x %s\n",
> im->m_class,
> - ntohl(addr.s_addr) >> 24 & 0xff,
> - ntohl(addr.s_addr) >> 16 & 0xff,
> - ntohl(addr.s_addr) >> 8 & 0xff,
> - ntohl(addr.s_addr) >> 0 & 0xff,
> + ntohl(addr.s6_addr32[3]) >> 16 & 0xffff,
> + ntohl(addr.s6_addr32[3]) & 0xffff,
> + ntohl(addr.s6_addr32[2]) >> 16 & 0xffff,
> + ntohl(addr.s6_addr32[2]) & 0xffff,
> + ntohl(addr.s6_addr32[1]) >> 16 & 0xffff,
> + ntohl(addr.s6_addr32[1]) & 0xffff,
> + ntohl(addr.s6_addr32[0]) >> 16 & 0xffff,
> + ntohl(addr.s6_addr32[0]) & 0xffff,
Again, s6_addr16[], and keep the dotted-quad for IPv4.
In fact ( borrowing Chuck's suggestion)
if (is_ipv4)
seq_printf(m, "%s "NIPQUAD_FMT" %s\n", im->m_class,
NIPQUAD((addr.s6_addr32[0])), ....);
else
seq_printf(m, "%s "NIP6_FMT" %s\n", im->m_class,
NIP6(addr), ...);
Thanks,
NeilBrown
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses
2007-08-09 15:14 ` Chuck Lever
@ 2007-08-10 1:11 ` Neil Brown
0 siblings, 0 replies; 11+ messages in thread
From: Neil Brown @ 2007-08-10 1:11 UTC (permalink / raw)
To: chuck.lever; +Cc: Aurélien Charbon, Mailing list NFSv4, netdev ML
On Thursday August 9, chuck.lever@oracle.com wrote:
> >>
> >> How have you tested the effectiveness of the new hash function?
> >
> > I have not tested that point but I can easily imagine there are better
> > solutions.
> > Perhaps we can keep the same function for an IPv4 address (only taking
> > the 32 bits of IPv4 addr), and then design one for IPv6 addresses.
>
> I see that, to generate the hash, you would be xor-ing the FF and 00
> bytes in the canonicalized IPv4 address. Yes, perhaps a better function
> is needed, or as you say, one specifically for IPv6 and one for
> canonicalized IPv4.
>
I suspect that the given hash function will be as good as any other.
The values in each byte of an IPv6 are likely to be either evenly
distributed, or constant.
Each the first case you don't need a clever hash function to
distribute them, while in the second, no hash function can improve the
distribution.
NeilBrown
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses
@ 2007-08-23 13:18 Aurélien Charbon
2007-08-23 15:32 ` Brian Haley
2007-08-23 15:39 ` Chuck Lever
0 siblings, 2 replies; 11+ messages in thread
From: Aurélien Charbon @ 2007-08-23 13:18 UTC (permalink / raw)
To: Mailing list NFSv4, netdev ML
According to Neil's comments, I have tried to correct the mistakes of my first sending
Thank you for these comments Neil.
This is a small part of missing pieces of IPv6 support for the server.
It deals with the ip_map caching code part.
It changes the ip_map structure to be able to store INET6 addresses.
It adds also the changes in address hashing, and mapping to test it with INET addresses.
Signed-off-by: Aurelien Charbon <aurelien.charbon@ext.bull.net>
---
fs/nfsd/export.c | 10 ++-
fs/nfsd/nfsctl.c | 21 ++++++-
include/linux/sunrpc/svcauth.h | 4 -
include/net/ipv6.h | 17 +++++
net/sunrpc/svcauth_unix.c | 121
++++++++++++++++++++++++++++-------------
5 files changed, 129 insertions(+), 44 deletions(-)
diff -p -u -r -N linux-2.6.23-rc3/fs/nfsd/export.c
linux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/export.c
--- linux-2.6.23-rc3/fs/nfsd/export.c 2007-08-23 13:18:16.000000000 +0200
+++ linux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/export.c 2007-08-23
13:51:08.000000000 +0200
@@ -35,6 +35,7 @@
#include <linux/lockd/bind.h>
#include <linux/sunrpc/msg_prot.h>
#include <linux/sunrpc/gss_api.h>
+#include <net/ipv6.h>
#define NFSDDBG_FACILITY NFSDDBG_EXPORT
@@ -1559,6 +1560,7 @@ exp_addclient(struct nfsctl_client *ncp)
{
struct auth_domain *dom;
int i, err;
+ struct in6_addr addr6;
/* First, consistency check. */
err = -EINVAL;
@@ -1577,9 +1579,11 @@ exp_addclient(struct nfsctl_client *ncp)
goto out_unlock;
/* Insert client into hashtable. */
- for (i = 0; i < ncp->cl_naddr; i++)
- auth_unix_add_addr(ncp->cl_addrlist[i], dom);
-
+ for (i = 0; i < ncp->cl_naddr; i++) {
+ /* Mapping address */
+ ipv6_addr_map(ncp->cl_addrlist[i], addr6);
+ auth_unix_add_addr(addr6, dom);
+ }
auth_unix_forget_old(dom);
auth_domain_put(dom);
diff -p -u -r -N linux-2.6.23-rc3/fs/nfsd/nfsctl.c
linux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/nfsctl.c
--- linux-2.6.23-rc3/fs/nfsd/nfsctl.c 2007-08-23 13:18:16.000000000 +0200
+++ linux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/nfsctl.c 2007-08-23
13:25:28.000000000 +0200
@@ -222,7 +222,7 @@ static ssize_t write_getfs(struct file *
struct auth_domain *clp;
int err = 0;
struct knfsd_fh *res;
-
+ struct in6_addr in6;
if (size < sizeof(*data))
return -EINVAL;
data = (struct nfsctl_fsparm*)buf;
@@ -236,7 +236,14 @@ static ssize_t write_getfs(struct file *
res = (struct knfsd_fh*)buf;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ in6.s6_addr32[0] = 0;
+ in6.s6_addr32[1] = 0;
+ in6.s6_addr32[2] = htonl(0xffff);
+ in6.s6_addr32[3] = (uint32_t)sin->sin_addr.s_addr;
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -253,6 +260,7 @@ static ssize_t write_getfd(struct file *
{
struct nfsctl_fdparm *data;
struct sockaddr_in *sin;
+ struct in6_addr in6;
struct auth_domain *clp;
int err = 0;
struct knfsd_fh fh;
@@ -271,7 +279,14 @@ static ssize_t write_getfd(struct file *
res = buf;
sin = (struct sockaddr_in *)&data->gd_addr;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ in6.s6_addr32[0] = 0;
+ in6.s6_addr32[1] = 0;
+ in6.s6_addr32[2] = htonl(0xffff);
+ in6.s6_addr32[3] = (uint32_t)sin->sin_addr.s_addr;
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
diff -p -u -r -N linux-2.6.23-rc3/include/linux/sunrpc/svcauth.h
linux-2.6.23-rc3-IPv6-ipmap-cache/include/linux/sunrpc/svcauth.h
--- linux-2.6.23-rc3/include/linux/sunrpc/svcauth.h 2007-08-23
13:18:21.000000000 +0200
+++ linux-2.6.23-rc3-IPv6-ipmap-cache/include/linux/sunrpc/svcauth.h
2007-08-23 13:25:28.000000000 +0200
@@ -120,10 +120,10 @@ extern void svc_auth_unregister(rpc_auth
extern struct auth_domain *unix_domain_find(char *name);
extern void auth_domain_put(struct auth_domain *item);
-extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain
*dom);
+extern int auth_unix_add_addr(struct in6_addr addr, struct auth_domain
*dom);
extern struct auth_domain *auth_domain_lookup(char *name, struct
auth_domain *new);
extern struct auth_domain *auth_domain_find(char *name);
-extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
+extern struct auth_domain *auth_unix_lookup(struct in6_addr addr);
extern int auth_unix_forget_old(struct auth_domain *dom);
extern void svcauth_unix_purge(void);
extern void svcauth_unix_info_release(void *);
diff -p -u -r -N linux-2.6.23-rc3/include/net/ipv6.h
linux-2.6.23-rc3-IPv6-ipmap-cache/include/net/ipv6.h
--- linux-2.6.23-rc3/include/net/ipv6.h 2007-08-23 13:18:23.000000000
+0200
+++ linux-2.6.23-rc3-IPv6-ipmap-cache/include/net/ipv6.h 2007-08-23
13:25:28.000000000 +0200
@@ -21,6 +21,7 @@
#include <net/ndisc.h>
#include <net/flow.h>
#include <net/snmp.h>
+#include <linux/in.h>
#define SIN6_LEN_RFC2133 24
@@ -167,6 +168,12 @@ DECLARE_SNMP_STAT(struct udp_mib, udplit
if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6,
field); \
else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0)
+#define IS_ADDR_MAPPED(a) \
+ (((uint32_t *) (a))[0] == 0 \
+ && ((uint32_t *) (a))[1] == 0 \
+ && (((uint32_t *) (a))[2] == 0 \
+ || ((uint32_t *) (a))[2] == htonl(0xffff)))
+
struct ip6_ra_chain
{
struct ip6_ra_chain *next;
@@ -377,6 +384,16 @@ static inline int ipv6_addr_any(const st
a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
}
+/* Maps a IPv4 address into a wright IPv6 address */
+static inline int ipv6_addr_map(const struct in_addr a1, struct
in6_addr a2)
+{
+ a2.s6_addr32[0] = 0;
+ a2.s6_addr32[1] = 0;
+ a2.s6_addr32[2] = htonl(0xffff);
+ a2.s6_addr32[3] = (uint32_t)a1.s_addr;
+ return 0;
+}
+
/*
* find the first different bit between two addresses
* length of address must be a multiple of 32bits
diff -p -u -r -N linux-2.6.23-rc3/net/sunrpc/svcauth_unix.c
linux-2.6.23-rc3-IPv6-ipmap-cache/net/sunrpc/svcauth_unix.c
--- linux-2.6.23-rc3/net/sunrpc/svcauth_unix.c 2007-08-23
13:18:24.000000000 +0200
+++ linux-2.6.23-rc3-IPv6-ipmap-cache/net/sunrpc/svcauth_unix.c
2007-08-23 13:52:02.000000000 +0200
@@ -11,7 +11,8 @@
#include <linux/hash.h>
#include <linux/string.h>
#include <net/sock.h>
-
+#include <net/ipv6.h>
+#include <linux/kernel.h>
#define RPCDBG_FACILITY RPCDBG_AUTH
@@ -84,7 +85,7 @@ static void svcauth_unix_domain_release(
struct ip_map {
struct cache_head h;
char m_class[8]; /* e.g. "nfsd" */
- struct in_addr m_addr;
+ struct in6_addr m_addr;
struct unix_domain *m_client;
int m_add_change;
};
@@ -112,12 +113,19 @@ static inline int hash_ip(__be32 ip)
return (hash ^ (hash>>8)) & 0xff;
}
#endif
+static inline int hash_ip6(struct in6_addr ip)
+{
+ return (hash_ip(ip.s6_addr32[0]) ^
+ hash_ip(ip.s6_addr32[1]) ^
+ hash_ip(ip.s6_addr32[2]) ^
+ hash_ip(ip.s6_addr32[3]));
+}
static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
{
struct ip_map *orig = container_of(corig, struct ip_map, h);
struct ip_map *new = container_of(cnew, struct ip_map, h);
return strcmp(orig->m_class, new->m_class) == 0
- && orig->m_addr.s_addr == new->m_addr.s_addr;
+ && ipv6_addr_equal(&orig->m_addr, &new->m_addr);
}
static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
{
@@ -125,7 +133,7 @@ static void ip_map_init(struct cache_hea
struct ip_map *item = container_of(citem, struct ip_map, h);
strcpy(new->m_class, item->m_class);
- new->m_addr.s_addr = item->m_addr.s_addr;
+ memcpy(&(new->m_addr), &(item->m_addr), sizeof(struct in6_addr));
}
static void update(struct cache_head *cnew, struct cache_head *citem)
{
@@ -151,20 +159,22 @@ static void ip_map_request(struct cache_
{
char text_addr[20];
struct ip_map *im = container_of(h, struct ip_map, h);
- __be32 addr = im->m_addr.s_addr;
-
- snprintf(text_addr, 20, "%u.%u.%u.%u",
- ntohl(addr) >> 24 & 0xff,
- ntohl(addr) >> 16 & 0xff,
- ntohl(addr) >> 8 & 0xff,
- ntohl(addr) >> 0 & 0xff);
+ if (IS_ADDR_MAPPED(im->m_addr.s6_addr32)) {
+ snprintf(text_addr, 20, NIPQUAD_FMT,
+ ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 8 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 0 & 0xff);
+ } else {
+ snprintf(text_addr, 20, NIP6_FMT, NIP6(im->m_addr));
+ }
qword_add(bpp, blen, im->m_class);
qword_add(bpp, blen, text_addr);
(*bpp)[-1] = '\n';
}
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr addr);
static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom,
time_t expiry);
static int ip_map_parse(struct cache_detail *cd,
@@ -175,10 +185,10 @@ static int ip_map_parse(struct cache_det
* for scratch: */
char *buf = mesg;
int len;
- int b1,b2,b3,b4;
+ int b1, b2, b3, b4, b5, b6, b7, b8;
char c;
char class[8];
- struct in_addr addr;
+ struct in6_addr addr;
int err;
struct ip_map *ipmp;
@@ -197,9 +207,26 @@ static int ip_map_parse(struct cache_det
len = qword_get(&mesg, buf, mlen);
if (len <= 0) return -EINVAL;
- if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
+ if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
+ addr.s6_addr32[0] = 0;
+ addr.s6_addr32[1] = 0;
+ addr.s6_addr32[2] = htonl(0xffff);
+ addr.s6_addr32[3] =
+ htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
+ } else if (sscanf(buf, NIP6_FMT "%c",
+ &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
+ addr.s6_addr16[7] = htons(b1);
+ addr.s6_addr16[6] = htons(b2);
+ addr.s6_addr16[5] = htons(b3);
+ addr.s6_addr16[4] = htons(b4);
+ addr.s6_addr16[3] = htons(b5);
+ addr.s6_addr16[2] = htons(b6);
+ addr.s6_addr16[1] = htons(b7);
+ addr.s6_addr16[0] = htons(b8);
+ } else
return -EINVAL;
+
expiry = get_expiry(&mesg);
if (expiry ==0)
return -EINVAL;
@@ -215,9 +242,6 @@ static int ip_map_parse(struct cache_det
} else
dom = NULL;
- addr.s_addr =
- htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
-
ipmp = ip_map_lookup(class,addr);
if (ipmp) {
err = ip_map_update(ipmp,
@@ -238,7 +262,7 @@ static int ip_map_show(struct seq_file *
struct cache_head *h)
{
struct ip_map *im;
- struct in_addr addr;
+ struct in6_addr addr;
char *dom = "-no-domain-";
if (h == NULL) {
@@ -247,20 +271,33 @@ static int ip_map_show(struct seq_file *
}
im = container_of(h, struct ip_map, h);
/* class addr domain */
- addr = im->m_addr;
+ memcpy(&addr, &im->m_addr, sizeof(struct in6_addr));
if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags))
dom = im->m_client->h.name;
- seq_printf(m, "%s %d.%d.%d.%d %s\n",
- im->m_class,
- ntohl(addr.s_addr) >> 24 & 0xff,
- ntohl(addr.s_addr) >> 16 & 0xff,
- ntohl(addr.s_addr) >> 8 & 0xff,
- ntohl(addr.s_addr) >> 0 & 0xff,
- dom
- );
+ if (IS_ADDR_MAPPED(addr.s6_addr32)) {
+ seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
+ im->m_class,
+ ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 8 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 0 & 0xff,
+ dom);
+ } else {
+ seq_printf(m, "%s" NIP6_FMT "%s\n",
+ im->m_class,
+ ntohl(addr.s6_addr16[7]),
+ ntohl(addr.s6_addr16[6]),
+ ntohl(addr.s6_addr16[5]),
+ ntohl(addr.s6_addr16[4]),
+ ntohl(addr.s6_addr16[3]),
+ ntohl(addr.s6_addr16[2]),
+ ntohl(addr.s6_addr16[1]),
+ ntohl(addr.s6_addr16[0]),
+ dom);
+ }
return 0;
}
@@ -280,16 +317,16 @@ struct cache_detail ip_map_cache = {
.alloc = ip_map_alloc,
};
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr addr)
{
struct ip_map ip;
struct cache_head *ch;
strcpy(ip.m_class, class);
- ip.m_addr = addr;
+ memcpy(&ip.m_addr, &addr, sizeof(struct in6_addr));
ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
hash_str(class, IP_HASHBITS) ^
- hash_ip(addr.s_addr));
+ hash_ip6(addr));
if (ch)
return container_of(ch, struct ip_map, h);
@@ -318,14 +355,14 @@ static int ip_map_update(struct ip_map *
ch = sunrpc_cache_update(&ip_map_cache,
&ip.h, &ipm->h,
hash_str(ipm->m_class, IP_HASHBITS) ^
- hash_ip(ipm->m_addr.s_addr));
+ hash_ip6(ipm->m_addr));
if (!ch)
return -ENOMEM;
cache_put(ch, &ip_map_cache);
return 0;
}
-int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
+int auth_unix_add_addr(struct in6_addr addr, struct auth_domain *dom)
{
struct unix_domain *udom;
struct ip_map *ipmp;
@@ -352,7 +389,7 @@ int auth_unix_forget_old(struct auth_dom
return 0;
}
-struct auth_domain *auth_unix_lookup(struct in_addr addr)
+struct auth_domain *auth_unix_lookup(struct in6_addr addr)
{
struct ip_map *ipm;
struct auth_domain *rv;
@@ -641,7 +678,19 @@ static int unix_gid_find(uid_t uid, stru
int
svcauth_unix_set_client(struct svc_rqst *rqstp)
{
- struct sockaddr_in *sin = svc_addr_in(rqstp);
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+
+ switch (rqstp->rq_addr.ss_family) {
+ default:
+ BUG();
+ case AF_INET:
+ sin = svc_addr_in(rqstp);
+ ipv6_addr_map(sin->sin_addr, sin6->sin6_addr);
+ case AF_INET6:
+ sin6 = svc_addr_in6(rqstp);
+ }
+
struct ip_map *ipm;
rqstp->rq_client = NULL;
@@ -651,7 +700,7 @@ svcauth_unix_set_client(struct svc_rqst
ipm = ip_map_cached_get(rqstp);
if (ipm == NULL)
ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
- sin->sin_addr);
+ sin6->sin6_addr);
if (ipm == NULL)
return SVC_DENIED;
--
********************************
Aurelien Charbon
Linux NFSv4 team
Bull SAS
Echirolles - France
http://nfsv4.bullopensource.org/
********************************
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses
2007-08-23 13:18 Aurélien Charbon
@ 2007-08-23 15:32 ` Brian Haley
2007-09-06 11:30 ` Aurélien Charbon
2007-08-23 15:39 ` Chuck Lever
1 sibling, 1 reply; 11+ messages in thread
From: Brian Haley @ 2007-08-23 15:32 UTC (permalink / raw)
To: Aurélien Charbon; +Cc: Mailing list NFSv4, netdev ML
Hi Aurelien,
Aurélien Charbon wrote:
> According to Neil's comments, I have tried to correct the mistakes of my
> first sending
I have some more comments.
> @@ -1559,6 +1560,7 @@ exp_addclient(struct nfsctl_client *ncp)
> {
> struct auth_domain *dom;
> int i, err;
> + struct in6_addr addr6;
Indentation looks wrong.
> diff -p -u -r -N linux-2.6.23-rc3/fs/nfsd/nfsctl.c
> linux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/nfsctl.c
> --- linux-2.6.23-rc3/fs/nfsd/nfsctl.c 2007-08-23 13:18:16.000000000
> +0200
> +++ linux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/nfsctl.c 2007-08-23
> 13:25:28.000000000 +0200
> @@ -222,7 +222,7 @@ static ssize_t write_getfs(struct file *
> struct auth_domain *clp;
> int err = 0;
> struct knfsd_fh *res;
> -
> + struct in6_addr in6;
Indentation.
> if (size < sizeof(*data))
> return -EINVAL;
> data = (struct nfsctl_fsparm*)buf;
> @@ -236,7 +236,14 @@ static ssize_t write_getfs(struct file *
> res = (struct knfsd_fh*)buf;
>
> exp_readlock();
> - if (!(clp = auth_unix_lookup(sin->sin_addr)))
> +
> + /* IPv6 address mapping */
> + in6.s6_addr32[0] = 0;
> + in6.s6_addr32[1] = 0;
> + in6.s6_addr32[2] = htonl(0xffff);
> + in6.s6_addr32[3] = (uint32_t)sin->sin_addr.s_addr;
Why didn't you use your new ipv6_addr_map() inline here?
> @@ -253,6 +260,7 @@ static ssize_t write_getfd(struct file *
> {
> struct nfsctl_fdparm *data;
> struct sockaddr_in *sin;
> + struct in6_addr in6;
Indentation.
> @@ -271,7 +279,14 @@ static ssize_t write_getfd(struct file *
> res = buf;
> sin = (struct sockaddr_in *)&data->gd_addr;
> exp_readlock();
> - if (!(clp = auth_unix_lookup(sin->sin_addr)))
> +
> + /* IPv6 address mapping */
> + in6.s6_addr32[0] = 0;
> + in6.s6_addr32[1] = 0;
> + in6.s6_addr32[2] = htonl(0xffff);
> + in6.s6_addr32[3] = (uint32_t)sin->sin_addr.s_addr;
Why didn't you use your new ipv6_addr_map() inline here too?
> diff -p -u -r -N linux-2.6.23-rc3/include/net/ipv6.h
> linux-2.6.23-rc3-IPv6-ipmap-cache/include/net/ipv6.h
> --- linux-2.6.23-rc3/include/net/ipv6.h 2007-08-23 13:18:23.000000000
> +0200
> +++ linux-2.6.23-rc3-IPv6-ipmap-cache/include/net/ipv6.h 2007-08-23
> 13:25:28.000000000 +0200
> @@ -21,6 +21,7 @@
> #include <net/ndisc.h>
> #include <net/flow.h>
> #include <net/snmp.h>
> +#include <linux/in.h>
>
> #define SIN6_LEN_RFC2133 24
>
> @@ -167,6 +168,12 @@ DECLARE_SNMP_STAT(struct udp_mib, udplit
> if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6,
> field); \
> else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0)
>
> +#define IS_ADDR_MAPPED(a) \
> + (((uint32_t *) (a))[0] == 0 \
> + && ((uint32_t *) (a))[1] == 0 \
> + && (((uint32_t *) (a))[2] == 0 \
> + || ((uint32_t *) (a))[2] == htonl(0xffff)))
I need to update a patch of mine that added a v4-mapped inline, let me
send that out. In the kernel you should use u32 too, is that why you
needed to include linux/net.h?
> +/* Maps a IPv4 address into a wright IPv6 address */
> +static inline int ipv6_addr_map(const struct in_addr a1, struct
> in6_addr a2)
> +{
> + a2.s6_addr32[0] = 0;
> + a2.s6_addr32[1] = 0;
> + a2.s6_addr32[2] = htonl(0xffff);
> + a2.s6_addr32[3] = (uint32_t)a1.s_addr;
> + return 0;
> +}
This can be void, noone ever checks the return status. Maybe change the
name to ipv6_addr_v4map() too?
> @@ -84,7 +85,7 @@ static void svcauth_unix_domain_release(
> struct ip_map {
> struct cache_head h;
> char m_class[8]; /* e.g. "nfsd" */
> - struct in_addr m_addr;
> + struct in6_addr m_addr;
Indentation.
> static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
> {
> @@ -125,7 +133,7 @@ static void ip_map_init(struct cache_hea
> struct ip_map *item = container_of(citem, struct ip_map, h);
>
> strcpy(new->m_class, item->m_class);
> - new->m_addr.s_addr = item->m_addr.s_addr;
> + memcpy(&(new->m_addr), &(item->m_addr), sizeof(struct in6_addr));
Use ipv6_addr_copy().
> @@ -151,20 +159,22 @@ static void ip_map_request(struct cache_
> {
> char text_addr[20];
> struct ip_map *im = container_of(h, struct ip_map, h);
> - __be32 addr = im->m_addr.s_addr;
> -
> - snprintf(text_addr, 20, "%u.%u.%u.%u",
> - ntohl(addr) >> 24 & 0xff,
> - ntohl(addr) >> 16 & 0xff,
> - ntohl(addr) >> 8 & 0xff,
> - ntohl(addr) >> 0 & 0xff);
>
> + if (IS_ADDR_MAPPED(im->m_addr.s6_addr32)) {
> + snprintf(text_addr, 20, NIPQUAD_FMT,
> + ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
> + ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
> + ntohl(im->m_addr.s6_addr32[3]) >> 8 & 0xff,
> + ntohl(im->m_addr.s6_addr32[3]) >> 0 & 0xff);
> + } else {
> + snprintf(text_addr, 20, NIP6_FMT, NIP6(im->m_addr));
> + }
You'll need more than 20 bytes to print an IPv6 address, I'd make this
at least 44 to account for some fluff. Surprised you didn't crash
during testing.
> static int ip_map_parse(struct cache_detail *cd,
> @@ -175,10 +185,10 @@ static int ip_map_parse(struct cache_det
> * for scratch: */
> char *buf = mesg;
> int len;
> - int b1,b2,b3,b4;
> + int b1, b2, b3, b4, b5, b6, b7, b8;
> char c;
> char class[8];
> - struct in_addr addr;
> + struct in6_addr addr;
> int err;
You might as well fix the indentation while you're here.
> @@ -238,7 +262,7 @@ static int ip_map_show(struct seq_file *
> struct cache_head *h)
> {
> struct ip_map *im;
> - struct in_addr addr;
> + struct in6_addr addr;
Indentation.
> if (h == NULL) {
> @@ -247,20 +271,33 @@ static int ip_map_show(struct seq_file *
> }
> im = container_of(h, struct ip_map, h);
> /* class addr domain */
> - addr = im->m_addr;
> + memcpy(&addr, &im->m_addr, sizeof(struct in6_addr));
ipv6_addr_copy()
> - seq_printf(m, "%s %d.%d.%d.%d %s\n",
> - im->m_class,
> - ntohl(addr.s_addr) >> 24 & 0xff,
> - ntohl(addr.s_addr) >> 16 & 0xff,
> - ntohl(addr.s_addr) >> 8 & 0xff,
> - ntohl(addr.s_addr) >> 0 & 0xff,
> - dom
> - );
> + if (IS_ADDR_MAPPED(addr.s6_addr32)) {
> + seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
> + im->m_class,
> + ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
> + ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
> + ntohl(addr.s6_addr32[3]) >> 8 & 0xff,
> + ntohl(addr.s6_addr32[3]) >> 0 & 0xff,
> + dom);
> + } else {
> + seq_printf(m, "%s" NIP6_FMT "%s\n",
> + im->m_class,
> + ntohl(addr.s6_addr16[7]),
> + ntohl(addr.s6_addr16[6]),
> + ntohl(addr.s6_addr16[5]),
> + ntohl(addr.s6_addr16[4]),
> + ntohl(addr.s6_addr16[3]),
> + ntohl(addr.s6_addr16[2]),
> + ntohl(addr.s6_addr16[1]),
> + ntohl(addr.s6_addr16[0]),
> + dom);
These should be ntohs(), it's only a 16-bit quantity. Also, don't you
want to start printing this at addr[0], not addr[7]?
> -static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
> +static struct ip_map *ip_map_lookup(char *class, struct in6_addr addr)
> {
> struct ip_map ip;
> struct cache_head *ch;
>
> strcpy(ip.m_class, class);
> - ip.m_addr = addr;
> + memcpy(&ip.m_addr, &addr, sizeof(struct in6_addr));
ipv6_addr_copy()
-Brian
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses
2007-08-23 13:18 Aurélien Charbon
2007-08-23 15:32 ` Brian Haley
@ 2007-08-23 15:39 ` Chuck Lever
1 sibling, 0 replies; 11+ messages in thread
From: Chuck Lever @ 2007-08-23 15:39 UTC (permalink / raw)
To: Aurélien Charbon; +Cc: Mailing list NFSv4, netdev ML
[-- Attachment #1: Type: text/plain, Size: 3989 bytes --]
Hi Aurélien-
Aurélien Charbon wrote:
> According to Neil's comments, I have tried to correct the mistakes of my first sending
> Thank you for these comments Neil.
>
> This is a small part of missing pieces of IPv6 support for the server.
> It deals with the ip_map caching code part.
>
> It changes the ip_map structure to be able to store INET6 addresses.
> It adds also the changes in address hashing, and mapping to test it with INET addresses.
>
> Signed-off-by: Aurelien Charbon <aurelien.charbon@ext.bull.net>
> ---
>
> fs/nfsd/export.c | 10 ++-
> fs/nfsd/nfsctl.c | 21 ++++++-
> include/linux/sunrpc/svcauth.h | 4 -
> include/net/ipv6.h | 17 +++++
> net/sunrpc/svcauth_unix.c | 121
> ++++++++++++++++++++++++++++-------------
> 5 files changed, 129 insertions(+), 44 deletions(-)
>
>
> diff -p -u -r -N linux-2.6.23-rc3/fs/nfsd/export.c
> linux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/export.c
> --- linux-2.6.23-rc3/fs/nfsd/export.c 2007-08-23 13:18:16.000000000 +0200
> +++ linux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/export.c 2007-08-23
> 13:51:08.000000000 +0200
> @@ -35,6 +35,7 @@
> #include <linux/lockd/bind.h>
> #include <linux/sunrpc/msg_prot.h>
> #include <linux/sunrpc/gss_api.h>
> +#include <net/ipv6.h>
>
> #define NFSDDBG_FACILITY NFSDDBG_EXPORT
>
> @@ -1559,6 +1560,7 @@ exp_addclient(struct nfsctl_client *ncp)
> {
> struct auth_domain *dom;
> int i, err;
> + struct in6_addr addr6;
>
> /* First, consistency check. */
> err = -EINVAL;
> @@ -1577,9 +1579,11 @@ exp_addclient(struct nfsctl_client *ncp)
> goto out_unlock;
>
> /* Insert client into hashtable. */
> - for (i = 0; i < ncp->cl_naddr; i++)
> - auth_unix_add_addr(ncp->cl_addrlist[i], dom);
> -
> + for (i = 0; i < ncp->cl_naddr; i++) {
> + /* Mapping address */
> + ipv6_addr_map(ncp->cl_addrlist[i], addr6);
> + auth_unix_add_addr(addr6, dom);
> + }
> auth_unix_forget_old(dom);
> auth_domain_put(dom);
>
> diff -p -u -r -N linux-2.6.23-rc3/fs/nfsd/nfsctl.c
> linux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/nfsctl.c
> --- linux-2.6.23-rc3/fs/nfsd/nfsctl.c 2007-08-23 13:18:16.000000000 +0200
> +++ linux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/nfsctl.c 2007-08-23
> 13:25:28.000000000 +0200
> @@ -222,7 +222,7 @@ static ssize_t write_getfs(struct file *
> struct auth_domain *clp;
> int err = 0;
> struct knfsd_fh *res;
> -
> + struct in6_addr in6;
> if (size < sizeof(*data))
> return -EINVAL;
> data = (struct nfsctl_fsparm*)buf;
> @@ -236,7 +236,14 @@ static ssize_t write_getfs(struct file *
> res = (struct knfsd_fh*)buf;
>
> exp_readlock();
> - if (!(clp = auth_unix_lookup(sin->sin_addr)))
> +
> + /* IPv6 address mapping */
> + in6.s6_addr32[0] = 0;
> + in6.s6_addr32[1] = 0;
> + in6.s6_addr32[2] = htonl(0xffff);
> + in6.s6_addr32[3] = (uint32_t)sin->sin_addr.s_addr;
> +
> + if (!(clp = auth_unix_lookup(in6)))
> err = -EPERM;
> else {
> err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
> @@ -253,6 +260,7 @@ static ssize_t write_getfd(struct file *
> {
> struct nfsctl_fdparm *data;
> struct sockaddr_in *sin;
> + struct in6_addr in6;
> struct auth_domain *clp;
> int err = 0;
> struct knfsd_fh fh;
> @@ -271,7 +279,14 @@ static ssize_t write_getfd(struct file *
> res = buf;
> sin = (struct sockaddr_in *)&data->gd_addr;
> exp_readlock();
> - if (!(clp = auth_unix_lookup(sin->sin_addr)))
> +
> + /* IPv6 address mapping */
> + in6.s6_addr32[0] = 0;
> + in6.s6_addr32[1] = 0;
> + in6.s6_addr32[2] = htonl(0xffff);
> + in6.s6_addr32[3] = (uint32_t)sin->sin_addr.s_addr;
The code canonicalizes IPv4 addresses in several places. Is there
already a generic function defined somewhere to do this? If not, it
might make sense to add one.
[-- Attachment #2: chuck.lever.vcf --]
[-- Type: text/x-vcard, Size: 302 bytes --]
begin:vcard
fn:Chuck Lever
n:Lever;Chuck
org:Oracle Corporation;Corporate Architecture: Linux Projects Group
adr:;;1015 Granger Avenue;Ann Arbor;MI;48104;USA
title:Principal Member of Staff
tel;work:+1 248 614 5091
x-mozilla-html:FALSE
url:http://oss.oracle.com/~cel
version:2.1
end:vcard
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses
2007-08-23 15:32 ` Brian Haley
@ 2007-09-06 11:30 ` Aurélien Charbon
2007-09-06 16:16 ` Brian Haley
0 siblings, 1 reply; 11+ messages in thread
From: Aurélien Charbon @ 2007-09-06 11:30 UTC (permalink / raw)
To: Brian Haley; +Cc: Mailing list NFSv4, netdev ML
[-- Attachment #1: Type: text/plain, Size: 13644 bytes --]
Thanks Chuck and Brian for your comments.
Here is some correction for the ip_map caching code part.
I have updated the code to use Brian's ipv6_addr_v4mapped function, and corrected some mistake you pointed out.
I have checked this patch with the checkpatch.pl script and i do not understand why the indentation is modified when sending it by mail (may be my mailer :-/). So i have added the patch in attachment.
Tests: tested with only IPv4 network and basic nfs ops (mount, file creation and modification)
Signed-off-by: Aurelien Charbon <aurelien.charbon@ext.bull.net>
---
fs/nfsd/export.c | 10 ++-
fs/nfsd/nfsctl.c | 16 ++++-
include/linux/sunrpc/svcauth.h | 4 -
include/net/ipv6.h | 15 +++++
net/sunrpc/svcauth_unix.c | 112 +++++++++++++++++++++++++++--------------
5 files changed, 113 insertions(+), 44 deletions(-)
diff -p -u -r -N linux-2.6.23-rc5/fs/nfsd/export.c linux-2.6.23-rc5-IPv6-ipmap-cache/fs/nfsd/export.c
--- linux-2.6.23-rc5/fs/nfsd/export.c 2007-09-04 13:55:02.000000000 +0200
+++ linux-2.6.23-rc5-IPv6-ipmap-cache/fs/nfsd/export.c 2007-09-04 17:05:47.000000000 +0200
@@ -35,6 +35,7 @@
#include <linux/lockd/bind.h>
#include <linux/sunrpc/msg_prot.h>
#include <linux/sunrpc/gss_api.h>
+#include <net/ipv6.h>
#define NFSDDBG_FACILITY NFSDDBG_EXPORT
@@ -1559,6 +1560,7 @@ exp_addclient(struct nfsctl_client *ncp)
{
struct auth_domain *dom;
int i, err;
+ struct in6_addr addr6;
/* First, consistency check. */
err = -EINVAL;
@@ -1577,9 +1579,11 @@ exp_addclient(struct nfsctl_client *ncp)
goto out_unlock;
/* Insert client into hashtable. */
- for (i = 0; i < ncp->cl_naddr; i++)
- auth_unix_add_addr(ncp->cl_addrlist[i], dom);
-
+ for (i = 0; i < ncp->cl_naddr; i++) {
+ /* Mapping address */
+ ipv6_addr_v4map(ncp->cl_addrlist[i], addr6);
+ auth_unix_add_addr(addr6, dom);
+ }
auth_unix_forget_old(dom);
auth_domain_put(dom);
diff -p -u -r -N linux-2.6.23-rc5/fs/nfsd/nfsctl.c linux-2.6.23-rc5-IPv6-ipmap-cache/fs/nfsd/nfsctl.c
--- linux-2.6.23-rc5/fs/nfsd/nfsctl.c 2007-09-04 13:55:02.000000000 +0200
+++ linux-2.6.23-rc5-IPv6-ipmap-cache/fs/nfsd/nfsctl.c 2007-09-06 11:17:00.000000000 +0200
@@ -38,6 +38,7 @@
#include <asm/uaccess.h>
+#include <net/ipv6.h>
/*
* We have a single directory with 9 nodes in it.
*/
@@ -222,7 +223,7 @@ static ssize_t write_getfs(struct file *
struct auth_domain *clp;
int err = 0;
struct knfsd_fh *res;
-
+ struct in6_addr in6;
if (size < sizeof(*data))
return -EINVAL;
data = (struct nfsctl_fsparm*)buf;
@@ -236,7 +237,11 @@ static ssize_t write_getfs(struct file *
res = (struct knfsd_fh*)buf;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ ipv6_addr_v4map(sin->sin_addr, in6);
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -253,6 +258,7 @@ static ssize_t write_getfd(struct file *
{
struct nfsctl_fdparm *data;
struct sockaddr_in *sin;
+ struct in6_addr in6;
struct auth_domain *clp;
int err = 0;
struct knfsd_fh fh;
@@ -271,7 +277,11 @@ static ssize_t write_getfd(struct file *
res = buf;
sin = (struct sockaddr_in *)&data->gd_addr;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ ipv6_addr_v4map(sin->sin_addr, in6);
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
diff -p -u -r -N linux-2.6.23-rc5/include/linux/sunrpc/svcauth.h linux-2.6.23-rc5-IPv6-ipmap-cache/include/linux/sunrpc/svcauth.h
--- linux-2.6.23-rc5/include/linux/sunrpc/svcauth.h 2007-09-04 13:55:03.000000000 +0200
+++ linux-2.6.23-rc5-IPv6-ipmap-cache/include/linux/sunrpc/svcauth.h 2007-09-04 14:37:21.000000000 +0200
@@ -120,10 +120,10 @@ extern void svc_auth_unregister(rpc_auth
extern struct auth_domain *unix_domain_find(char *name);
extern void auth_domain_put(struct auth_domain *item);
-extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom);
+extern int auth_unix_add_addr(struct in6_addr addr, struct auth_domain *dom);
extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
extern struct auth_domain *auth_domain_find(char *name);
-extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
+extern struct auth_domain *auth_unix_lookup(struct in6_addr addr);
extern int auth_unix_forget_old(struct auth_domain *dom);
extern void svcauth_unix_purge(void);
extern void svcauth_unix_info_release(void *);
diff -p -u -r -N linux-2.6.23-rc5/include/net/ipv6.h linux-2.6.23-rc5-IPv6-ipmap-cache/include/net/ipv6.h
--- linux-2.6.23-rc5/include/net/ipv6.h 2007-09-04 16:32:38.000000000 +0200
+++ linux-2.6.23-rc5-IPv6-ipmap-cache/include/net/ipv6.h 2007-09-05 10:01:51.000000000 +0200
@@ -21,6 +21,7 @@
#include <net/ndisc.h>
#include <net/flow.h>
#include <net/snmp.h>
+#include <linux/in.h>
#define SIN6_LEN_RFC2133 24
@@ -167,6 +168,12 @@ DECLARE_SNMP_STAT(struct udp_mib, udplit
if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field); \
else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0)
+#define IS_ADDR_MAPPED(a) \
+ (((uint32_t *) (a))[0] == 0 \
+ && ((uint32_t *) (a))[1] == 0 \
+ && (((uint32_t *) (a))[2] == 0 \
+ || ((uint32_t *) (a))[2] == htonl(0xffff)))
+
struct ip6_ra_chain
{
struct ip6_ra_chain *next;
@@ -377,6 +384,14 @@ static inline int ipv6_addr_any(const st
a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
}
+static inline void ipv6_addr_v4map(const struct in_addr a1, struct in6_addr a2)
+{
+ a2.s6_addr32[0] = 0;
+ a2.s6_addr32[1] = 0;
+ a2.s6_addr32[2] = htonl(0xffff);
+ a2.s6_addr32[3] = (uint32_t)a1.s_addr;
+}
+
static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
{
return ((a->s6_addr32[0] | a->s6_addr32[1]) == 0 &&
diff -p -u -r -N linux-2.6.23-rc5/net/sunrpc/svcauth_unix.c linux-2.6.23-rc5-IPv6-ipmap-cache/net/sunrpc/svcauth_unix.c
--- linux-2.6.23-rc5/net/sunrpc/svcauth_unix.c 2007-09-04 13:55:04.000000000 +0200
+++ linux-2.6.23-rc5-IPv6-ipmap-cache/net/sunrpc/svcauth_unix.c 2007-09-06 10:30:19.000000000 +0200
@@ -11,7 +11,8 @@
#include <linux/hash.h>
#include <linux/string.h>
#include <net/sock.h>
-
+#include <net/ipv6.h>
+#include <linux/kernel.h>
#define RPCDBG_FACILITY RPCDBG_AUTH
@@ -84,7 +85,7 @@ static void svcauth_unix_domain_release(
struct ip_map {
struct cache_head h;
char m_class[8]; /* e.g. "nfsd" */
- struct in_addr m_addr;
+ struct in6_addr m_addr;
struct unix_domain *m_client;
int m_add_change;
};
@@ -112,12 +113,19 @@ static inline int hash_ip(__be32 ip)
return (hash ^ (hash>>8)) & 0xff;
}
#endif
+static inline int hash_ip6(struct in6_addr ip)
+{
+ return (hash_ip(ip.s6_addr32[0]) ^
+ hash_ip(ip.s6_addr32[1]) ^
+ hash_ip(ip.s6_addr32[2]) ^
+ hash_ip(ip.s6_addr32[3]));
+}
static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
{
struct ip_map *orig = container_of(corig, struct ip_map, h);
struct ip_map *new = container_of(cnew, struct ip_map, h);
return strcmp(orig->m_class, new->m_class) == 0
- && orig->m_addr.s_addr == new->m_addr.s_addr;
+ && ipv6_addr_equal(&orig->m_addr, &new->m_addr);
}
static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
{
@@ -125,7 +133,7 @@ static void ip_map_init(struct cache_hea
struct ip_map *item = container_of(citem, struct ip_map, h);
strcpy(new->m_class, item->m_class);
- new->m_addr.s_addr = item->m_addr.s_addr;
+ ipv6_addr_copy(&(new->m_addr), &(item->m_addr));
}
static void update(struct cache_head *cnew, struct cache_head *citem)
{
@@ -151,20 +159,22 @@ static void ip_map_request(struct cache_
{
char text_addr[20];
struct ip_map *im = container_of(h, struct ip_map, h);
- __be32 addr = im->m_addr.s_addr;
-
- snprintf(text_addr, 20, "%u.%u.%u.%u",
- ntohl(addr) >> 24 & 0xff,
- ntohl(addr) >> 16 & 0xff,
- ntohl(addr) >> 8 & 0xff,
- ntohl(addr) >> 0 & 0xff);
+ if (ipv6_addr_v4mapped(&(im->m_addr))) {
+ snprintf(text_addr, 20, NIPQUAD_FMT,
+ ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 8 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 0 & 0xff);
+ } else {
+ snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
+ }
qword_add(bpp, blen, im->m_class);
qword_add(bpp, blen, text_addr);
(*bpp)[-1] = '\n';
}
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr addr);
static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
static int ip_map_parse(struct cache_detail *cd,
@@ -175,10 +185,10 @@ static int ip_map_parse(struct cache_det
* for scratch: */
char *buf = mesg;
int len;
- int b1,b2,b3,b4;
+ int b1, b2, b3, b4, b5, b6, b7, b8;
char c;
char class[8];
- struct in_addr addr;
+ struct in6_addr addr;
int err;
struct ip_map *ipmp;
@@ -197,9 +207,26 @@ static int ip_map_parse(struct cache_det
len = qword_get(&mesg, buf, mlen);
if (len <= 0) return -EINVAL;
- if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
+ if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
+ addr.s6_addr32[0] = 0;
+ addr.s6_addr32[1] = 0;
+ addr.s6_addr32[2] = htonl(0xffff);
+ addr.s6_addr32[3] =
+ htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
+ } else if (sscanf(buf, NIP6_FMT "%c",
+ &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
+ addr.s6_addr16[0] = htons(b1);
+ addr.s6_addr16[1] = htons(b2);
+ addr.s6_addr16[2] = htons(b3);
+ addr.s6_addr16[3] = htons(b4);
+ addr.s6_addr16[4] = htons(b5);
+ addr.s6_addr16[5] = htons(b6);
+ addr.s6_addr16[6] = htons(b7);
+ addr.s6_addr16[7] = htons(b8);
+ } else
return -EINVAL;
+
expiry = get_expiry(&mesg);
if (expiry ==0)
return -EINVAL;
@@ -215,9 +242,6 @@ static int ip_map_parse(struct cache_det
} else
dom = NULL;
- addr.s_addr =
- htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
-
ipmp = ip_map_lookup(class,addr);
if (ipmp) {
err = ip_map_update(ipmp,
@@ -238,7 +262,7 @@ static int ip_map_show(struct seq_file *
struct cache_head *h)
{
struct ip_map *im;
- struct in_addr addr;
+ struct in6_addr addr;
char *dom = "-no-domain-";
if (h == NULL) {
@@ -247,20 +271,24 @@ static int ip_map_show(struct seq_file *
}
im = container_of(h, struct ip_map, h);
/* class addr domain */
- addr = im->m_addr;
+ ipv6_addr_copy(&addr, &im->m_addr);
if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags))
dom = im->m_client->h.name;
- seq_printf(m, "%s %d.%d.%d.%d %s\n",
- im->m_class,
- ntohl(addr.s_addr) >> 24 & 0xff,
- ntohl(addr.s_addr) >> 16 & 0xff,
- ntohl(addr.s_addr) >> 8 & 0xff,
- ntohl(addr.s_addr) >> 0 & 0xff,
- dom
- );
+ if (ipv6_addr_v4mapped(&addr)) {
+ seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
+ im->m_class,
+ ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 8 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 0 & 0xff,
+ dom);
+ } else {
+ seq_printf(m, "%s" NIP6_FMT "%s\n",
+ im->m_class, NIP6(addr), dom);
+ }
return 0;
}
@@ -280,16 +308,16 @@ struct cache_detail ip_map_cache = {
.alloc = ip_map_alloc,
};
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr addr)
{
struct ip_map ip;
struct cache_head *ch;
strcpy(ip.m_class, class);
- ip.m_addr = addr;
+ ipv6_addr_copy(&ip.m_addr, &addr);
ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
hash_str(class, IP_HASHBITS) ^
- hash_ip(addr.s_addr));
+ hash_ip6(addr));
if (ch)
return container_of(ch, struct ip_map, h);
@@ -318,14 +346,14 @@ static int ip_map_update(struct ip_map *
ch = sunrpc_cache_update(&ip_map_cache,
&ip.h, &ipm->h,
hash_str(ipm->m_class, IP_HASHBITS) ^
- hash_ip(ipm->m_addr.s_addr));
+ hash_ip6(ipm->m_addr));
if (!ch)
return -ENOMEM;
cache_put(ch, &ip_map_cache);
return 0;
}
-int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
+int auth_unix_add_addr(struct in6_addr addr, struct auth_domain *dom)
{
struct unix_domain *udom;
struct ip_map *ipmp;
@@ -352,7 +380,7 @@ int auth_unix_forget_old(struct auth_dom
return 0;
}
-struct auth_domain *auth_unix_lookup(struct in_addr addr)
+struct auth_domain *auth_unix_lookup(struct in6_addr addr)
{
struct ip_map *ipm;
struct auth_domain *rv;
@@ -641,7 +669,19 @@ static int unix_gid_find(uid_t uid, stru
int
svcauth_unix_set_client(struct svc_rqst *rqstp)
{
- struct sockaddr_in *sin = svc_addr_in(rqstp);
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+
+ switch (rqstp->rq_addr.ss_family) {
+ default:
+ BUG();
+ case AF_INET:
+ sin = svc_addr_in(rqstp);
+ ipv6_addr_v4map(sin->sin_addr, sin6->sin6_addr);
+ case AF_INET6:
+ sin6 = svc_addr_in6(rqstp);
+ }
+
struct ip_map *ipm;
rqstp->rq_client = NULL;
@@ -651,7 +691,7 @@ svcauth_unix_set_client(struct svc_rqst
ipm = ip_map_cached_get(rqstp);
if (ipm == NULL)
ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
- sin->sin_addr);
+ sin6->sin6_addr);
if (ipm == NULL)
return SVC_DENIED;
--
********************************
Aurelien Charbon
Linux NFSv4 team
Bull SAS
Echirolles - France
http://nfsv4.bullopensource.org/
********************************
[-- Attachment #2: linux-2.6.23-rc5-IPv6-ipmap-cache.diff --]
[-- Type: text/x-patch, Size: 12899 bytes --]
This is a small part of missing pieces of IPv6 support for the server.
It deals with the ip_map caching code part.
It changes the ip_map structure to be able to store INET6 addresses.
It adds also the changes in address hashing, and mapping to test it with INET addresses.
Signed-off-by: Aurelien Charbon <aurelien.charbon@ext.bull.net>
---
diff -p -u -r -N linux-2.6.23-rc5/fs/nfsd/export.c linux-2.6.23-rc5-IPv6-ipmap-cache/fs/nfsd/export.c
--- linux-2.6.23-rc5/fs/nfsd/export.c 2007-09-04 13:55:02.000000000 +0200
+++ linux-2.6.23-rc5-IPv6-ipmap-cache/fs/nfsd/export.c 2007-09-04 17:05:47.000000000 +0200
@@ -35,6 +35,7 @@
#include <linux/lockd/bind.h>
#include <linux/sunrpc/msg_prot.h>
#include <linux/sunrpc/gss_api.h>
+#include <net/ipv6.h>
#define NFSDDBG_FACILITY NFSDDBG_EXPORT
@@ -1559,6 +1560,7 @@ exp_addclient(struct nfsctl_client *ncp)
{
struct auth_domain *dom;
int i, err;
+ struct in6_addr addr6;
/* First, consistency check. */
err = -EINVAL;
@@ -1577,9 +1579,11 @@ exp_addclient(struct nfsctl_client *ncp)
goto out_unlock;
/* Insert client into hashtable. */
- for (i = 0; i < ncp->cl_naddr; i++)
- auth_unix_add_addr(ncp->cl_addrlist[i], dom);
-
+ for (i = 0; i < ncp->cl_naddr; i++) {
+ /* Mapping address */
+ ipv6_addr_v4map(ncp->cl_addrlist[i], addr6);
+ auth_unix_add_addr(addr6, dom);
+ }
auth_unix_forget_old(dom);
auth_domain_put(dom);
diff -p -u -r -N linux-2.6.23-rc5/fs/nfsd/nfsctl.c linux-2.6.23-rc5-IPv6-ipmap-cache/fs/nfsd/nfsctl.c
--- linux-2.6.23-rc5/fs/nfsd/nfsctl.c 2007-09-04 13:55:02.000000000 +0200
+++ linux-2.6.23-rc5-IPv6-ipmap-cache/fs/nfsd/nfsctl.c 2007-09-06 11:17:00.000000000 +0200
@@ -38,6 +38,7 @@
#include <asm/uaccess.h>
+#include <net/ipv6.h>
/*
* We have a single directory with 9 nodes in it.
*/
@@ -222,7 +223,7 @@ static ssize_t write_getfs(struct file *
struct auth_domain *clp;
int err = 0;
struct knfsd_fh *res;
-
+ struct in6_addr in6;
if (size < sizeof(*data))
return -EINVAL;
data = (struct nfsctl_fsparm*)buf;
@@ -236,7 +237,11 @@ static ssize_t write_getfs(struct file *
res = (struct knfsd_fh*)buf;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ ipv6_addr_v4map(sin->sin_addr, in6);
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -253,6 +258,7 @@ static ssize_t write_getfd(struct file *
{
struct nfsctl_fdparm *data;
struct sockaddr_in *sin;
+ struct in6_addr in6;
struct auth_domain *clp;
int err = 0;
struct knfsd_fh fh;
@@ -271,7 +277,11 @@ static ssize_t write_getfd(struct file *
res = buf;
sin = (struct sockaddr_in *)&data->gd_addr;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ ipv6_addr_v4map(sin->sin_addr, in6);
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
diff -p -u -r -N linux-2.6.23-rc5/include/linux/sunrpc/svcauth.h linux-2.6.23-rc5-IPv6-ipmap-cache/include/linux/sunrpc/svcauth.h
--- linux-2.6.23-rc5/include/linux/sunrpc/svcauth.h 2007-09-04 13:55:03.000000000 +0200
+++ linux-2.6.23-rc5-IPv6-ipmap-cache/include/linux/sunrpc/svcauth.h 2007-09-04 14:37:21.000000000 +0200
@@ -120,10 +120,10 @@ extern void svc_auth_unregister(rpc_auth
extern struct auth_domain *unix_domain_find(char *name);
extern void auth_domain_put(struct auth_domain *item);
-extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom);
+extern int auth_unix_add_addr(struct in6_addr addr, struct auth_domain *dom);
extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
extern struct auth_domain *auth_domain_find(char *name);
-extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
+extern struct auth_domain *auth_unix_lookup(struct in6_addr addr);
extern int auth_unix_forget_old(struct auth_domain *dom);
extern void svcauth_unix_purge(void);
extern void svcauth_unix_info_release(void *);
diff -p -u -r -N linux-2.6.23-rc5/include/net/ipv6.h linux-2.6.23-rc5-IPv6-ipmap-cache/include/net/ipv6.h
--- linux-2.6.23-rc5/include/net/ipv6.h 2007-09-04 16:32:38.000000000 +0200
+++ linux-2.6.23-rc5-IPv6-ipmap-cache/include/net/ipv6.h 2007-09-05 10:01:51.000000000 +0200
@@ -21,6 +21,7 @@
#include <net/ndisc.h>
#include <net/flow.h>
#include <net/snmp.h>
+#include <linux/in.h>
#define SIN6_LEN_RFC2133 24
@@ -167,6 +168,12 @@ DECLARE_SNMP_STAT(struct udp_mib, udplit
if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field); \
else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0)
+#define IS_ADDR_MAPPED(a) \
+ (((uint32_t *) (a))[0] == 0 \
+ && ((uint32_t *) (a))[1] == 0 \
+ && (((uint32_t *) (a))[2] == 0 \
+ || ((uint32_t *) (a))[2] == htonl(0xffff)))
+
struct ip6_ra_chain
{
struct ip6_ra_chain *next;
@@ -377,6 +384,14 @@ static inline int ipv6_addr_any(const st
a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
}
+static inline void ipv6_addr_v4map(const struct in_addr a1, struct in6_addr a2)
+{
+ a2.s6_addr32[0] = 0;
+ a2.s6_addr32[1] = 0;
+ a2.s6_addr32[2] = htonl(0xffff);
+ a2.s6_addr32[3] = (uint32_t)a1.s_addr;
+}
+
static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
{
return ((a->s6_addr32[0] | a->s6_addr32[1]) == 0 &&
diff -p -u -r -N linux-2.6.23-rc5/net/sunrpc/svcauth_unix.c linux-2.6.23-rc5-IPv6-ipmap-cache/net/sunrpc/svcauth_unix.c
--- linux-2.6.23-rc5/net/sunrpc/svcauth_unix.c 2007-09-04 13:55:04.000000000 +0200
+++ linux-2.6.23-rc5-IPv6-ipmap-cache/net/sunrpc/svcauth_unix.c 2007-09-06 10:30:19.000000000 +0200
@@ -11,7 +11,8 @@
#include <linux/hash.h>
#include <linux/string.h>
#include <net/sock.h>
-
+#include <net/ipv6.h>
+#include <linux/kernel.h>
#define RPCDBG_FACILITY RPCDBG_AUTH
@@ -84,7 +85,7 @@ static void svcauth_unix_domain_release(
struct ip_map {
struct cache_head h;
char m_class[8]; /* e.g. "nfsd" */
- struct in_addr m_addr;
+ struct in6_addr m_addr;
struct unix_domain *m_client;
int m_add_change;
};
@@ -112,12 +113,19 @@ static inline int hash_ip(__be32 ip)
return (hash ^ (hash>>8)) & 0xff;
}
#endif
+static inline int hash_ip6(struct in6_addr ip)
+{
+ return (hash_ip(ip.s6_addr32[0]) ^
+ hash_ip(ip.s6_addr32[1]) ^
+ hash_ip(ip.s6_addr32[2]) ^
+ hash_ip(ip.s6_addr32[3]));
+}
static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
{
struct ip_map *orig = container_of(corig, struct ip_map, h);
struct ip_map *new = container_of(cnew, struct ip_map, h);
return strcmp(orig->m_class, new->m_class) == 0
- && orig->m_addr.s_addr == new->m_addr.s_addr;
+ && ipv6_addr_equal(&orig->m_addr, &new->m_addr);
}
static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
{
@@ -125,7 +133,7 @@ static void ip_map_init(struct cache_hea
struct ip_map *item = container_of(citem, struct ip_map, h);
strcpy(new->m_class, item->m_class);
- new->m_addr.s_addr = item->m_addr.s_addr;
+ ipv6_addr_copy(&(new->m_addr), &(item->m_addr));
}
static void update(struct cache_head *cnew, struct cache_head *citem)
{
@@ -151,20 +159,22 @@ static void ip_map_request(struct cache_
{
char text_addr[20];
struct ip_map *im = container_of(h, struct ip_map, h);
- __be32 addr = im->m_addr.s_addr;
-
- snprintf(text_addr, 20, "%u.%u.%u.%u",
- ntohl(addr) >> 24 & 0xff,
- ntohl(addr) >> 16 & 0xff,
- ntohl(addr) >> 8 & 0xff,
- ntohl(addr) >> 0 & 0xff);
+ if (ipv6_addr_v4mapped(&(im->m_addr))) {
+ snprintf(text_addr, 20, NIPQUAD_FMT,
+ ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 8 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 0 & 0xff);
+ } else {
+ snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
+ }
qword_add(bpp, blen, im->m_class);
qword_add(bpp, blen, text_addr);
(*bpp)[-1] = '\n';
}
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr addr);
static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
static int ip_map_parse(struct cache_detail *cd,
@@ -175,10 +185,10 @@ static int ip_map_parse(struct cache_det
* for scratch: */
char *buf = mesg;
int len;
- int b1,b2,b3,b4;
+ int b1, b2, b3, b4, b5, b6, b7, b8;
char c;
char class[8];
- struct in_addr addr;
+ struct in6_addr addr;
int err;
struct ip_map *ipmp;
@@ -197,9 +207,26 @@ static int ip_map_parse(struct cache_det
len = qword_get(&mesg, buf, mlen);
if (len <= 0) return -EINVAL;
- if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
+ if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
+ addr.s6_addr32[0] = 0;
+ addr.s6_addr32[1] = 0;
+ addr.s6_addr32[2] = htonl(0xffff);
+ addr.s6_addr32[3] =
+ htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
+ } else if (sscanf(buf, NIP6_FMT "%c",
+ &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
+ addr.s6_addr16[0] = htons(b1);
+ addr.s6_addr16[1] = htons(b2);
+ addr.s6_addr16[2] = htons(b3);
+ addr.s6_addr16[3] = htons(b4);
+ addr.s6_addr16[4] = htons(b5);
+ addr.s6_addr16[5] = htons(b6);
+ addr.s6_addr16[6] = htons(b7);
+ addr.s6_addr16[7] = htons(b8);
+ } else
return -EINVAL;
+
expiry = get_expiry(&mesg);
if (expiry ==0)
return -EINVAL;
@@ -215,9 +242,6 @@ static int ip_map_parse(struct cache_det
} else
dom = NULL;
- addr.s_addr =
- htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
-
ipmp = ip_map_lookup(class,addr);
if (ipmp) {
err = ip_map_update(ipmp,
@@ -238,7 +262,7 @@ static int ip_map_show(struct seq_file *
struct cache_head *h)
{
struct ip_map *im;
- struct in_addr addr;
+ struct in6_addr addr;
char *dom = "-no-domain-";
if (h == NULL) {
@@ -247,20 +271,24 @@ static int ip_map_show(struct seq_file *
}
im = container_of(h, struct ip_map, h);
/* class addr domain */
- addr = im->m_addr;
+ ipv6_addr_copy(&addr, &im->m_addr);
if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags))
dom = im->m_client->h.name;
- seq_printf(m, "%s %d.%d.%d.%d %s\n",
- im->m_class,
- ntohl(addr.s_addr) >> 24 & 0xff,
- ntohl(addr.s_addr) >> 16 & 0xff,
- ntohl(addr.s_addr) >> 8 & 0xff,
- ntohl(addr.s_addr) >> 0 & 0xff,
- dom
- );
+ if (ipv6_addr_v4mapped(&addr)) {
+ seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
+ im->m_class,
+ ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 8 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 0 & 0xff,
+ dom);
+ } else {
+ seq_printf(m, "%s" NIP6_FMT "%s\n",
+ im->m_class, NIP6(addr), dom);
+ }
return 0;
}
@@ -280,16 +308,16 @@ struct cache_detail ip_map_cache = {
.alloc = ip_map_alloc,
};
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr addr)
{
struct ip_map ip;
struct cache_head *ch;
strcpy(ip.m_class, class);
- ip.m_addr = addr;
+ ipv6_addr_copy(&ip.m_addr, &addr);
ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
hash_str(class, IP_HASHBITS) ^
- hash_ip(addr.s_addr));
+ hash_ip6(addr));
if (ch)
return container_of(ch, struct ip_map, h);
@@ -318,14 +346,14 @@ static int ip_map_update(struct ip_map *
ch = sunrpc_cache_update(&ip_map_cache,
&ip.h, &ipm->h,
hash_str(ipm->m_class, IP_HASHBITS) ^
- hash_ip(ipm->m_addr.s_addr));
+ hash_ip6(ipm->m_addr));
if (!ch)
return -ENOMEM;
cache_put(ch, &ip_map_cache);
return 0;
}
-int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
+int auth_unix_add_addr(struct in6_addr addr, struct auth_domain *dom)
{
struct unix_domain *udom;
struct ip_map *ipmp;
@@ -352,7 +380,7 @@ int auth_unix_forget_old(struct auth_dom
return 0;
}
-struct auth_domain *auth_unix_lookup(struct in_addr addr)
+struct auth_domain *auth_unix_lookup(struct in6_addr addr)
{
struct ip_map *ipm;
struct auth_domain *rv;
@@ -641,7 +669,19 @@ static int unix_gid_find(uid_t uid, stru
int
svcauth_unix_set_client(struct svc_rqst *rqstp)
{
- struct sockaddr_in *sin = svc_addr_in(rqstp);
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+
+ switch (rqstp->rq_addr.ss_family) {
+ default:
+ BUG();
+ case AF_INET:
+ sin = svc_addr_in(rqstp);
+ ipv6_addr_v4map(sin->sin_addr, sin6->sin6_addr);
+ case AF_INET6:
+ sin6 = svc_addr_in6(rqstp);
+ }
+
struct ip_map *ipm;
rqstp->rq_client = NULL;
@@ -651,7 +691,7 @@ svcauth_unix_set_client(struct svc_rqst
ipm = ip_map_cached_get(rqstp);
if (ipm == NULL)
ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
- sin->sin_addr);
+ sin6->sin6_addr);
if (ipm == NULL)
return SVC_DENIED;
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses
2007-09-06 11:30 ` Aurélien Charbon
@ 2007-09-06 16:16 ` Brian Haley
0 siblings, 0 replies; 11+ messages in thread
From: Brian Haley @ 2007-09-06 16:16 UTC (permalink / raw)
To: Aurélien Charbon; +Cc: Mailing list NFSv4, netdev ML
Hi Aurelien,
More comments.
Aurélien Charbon wrote:
> This is a small part of missing pieces of IPv6 support for the server.
> It deals with the ip_map caching code part.
> /* Insert client into hashtable. */
> - for (i = 0; i < ncp->cl_naddr; i++)
> - auth_unix_add_addr(ncp->cl_addrlist[i], dom);
> -
> + for (i = 0; i < ncp->cl_naddr; i++) {
> + /* Mapping address */
> + ipv6_addr_v4map(ncp->cl_addrlist[i], addr6);
ipv6_addr_set(&addr6, 0, 0, htonl(0x0000FFFF), ncp->cl_addrlist[i]);
See below.
> @@ -236,7 +237,11 @@ static ssize_t write_getfs(struct file *
> res = (struct knfsd_fh*)buf;
>
> exp_readlock();
> - if (!(clp = auth_unix_lookup(sin->sin_addr)))
> +
> + /* IPv6 address mapping */
> + ipv6_addr_v4map(sin->sin_addr, in6);
ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), sin->sin_addr);
See below.
> @@ -271,7 +277,11 @@ static ssize_t write_getfd(struct file *
> res = buf;
> sin = (struct sockaddr_in *)&data->gd_addr;
> exp_readlock();
> - if (!(clp = auth_unix_lookup(sin->sin_addr)))
> +
> + /* IPv6 address mapping */
> + ipv6_addr_v4map(sin->sin_addr, in6);
ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), sin->sin_addr);
See below.
> +#define IS_ADDR_MAPPED(a) \
> + (((uint32_t *) (a))[0] == 0 \
> + && ((uint32_t *) (a))[1] == 0 \
> + && (((uint32_t *) (a))[2] == 0 \
> + || ((uint32_t *) (a))[2] == htonl(0xffff)))
Can go away, right?
> +static inline void ipv6_addr_v4map(const struct in_addr a1, struct in6_addr a2)
> +{
> + a2.s6_addr32[0] = 0;
> + a2.s6_addr32[1] = 0;
> + a2.s6_addr32[2] = htonl(0xffff);
> + a2.s6_addr32[3] = (uint32_t)a1.s_addr;
> +}
This can go away. Looking at other code that does this - TCP, UDP,
DCCP, they just call ipv6_addr_set() directly.
> +static inline int hash_ip6(struct in6_addr ip)
> +{
> + return (hash_ip(ip.s6_addr32[0]) ^
> + hash_ip(ip.s6_addr32[1]) ^
> + hash_ip(ip.s6_addr32[2]) ^
> + hash_ip(ip.s6_addr32[3]));
> +}
Should probably use a pointer to the address (*ip), probably doesn't
matter that much since it's an inline.
> @@ -151,20 +159,22 @@ static void ip_map_request(struct cache_
> {
> char text_addr[20];
This needs to be at least 40 since you're passing that to snprintf() below.
> + if (ipv6_addr_v4mapped(&(im->m_addr))) {
> + snprintf(text_addr, 20, NIPQUAD_FMT,
> + ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
> + ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
> + ntohl(im->m_addr.s6_addr32[3]) >> 8 & 0xff,
> + ntohl(im->m_addr.s6_addr32[3]) >> 0 & 0xff);
> + } else {
> + snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
> + }
Here -------------------------------^^
> -static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
> +static struct ip_map *ip_map_lookup(char *class, struct in6_addr addr)
Maybe you should pass a pointer to the address (*addr) to avoid passing
it on the stack.
> -int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
> +int auth_unix_add_addr(struct in6_addr addr, struct auth_domain *dom)
Here too.
> -struct auth_domain *auth_unix_lookup(struct in_addr addr)
> +struct auth_domain *auth_unix_lookup(struct in6_addr addr)
Here too.
> @@ -641,7 +669,19 @@ static int unix_gid_find(uid_t uid, stru
> int
> svcauth_unix_set_client(struct svc_rqst *rqstp)
> {
> - struct sockaddr_in *sin = svc_addr_in(rqstp);
> + struct sockaddr_in *sin;
> + struct sockaddr_in6 *sin6;
Will need change this to something like:
> + struct sockaddr_in6 *sin6, sin6_storage;
See below.
> +
> + switch (rqstp->rq_addr.ss_family) {
> + default:
> + BUG();
> + case AF_INET:
> + sin = svc_addr_in(rqstp);
> + ipv6_addr_v4map(sin->sin_addr, sin6->sin6_addr);
sin6 here is uninitialized, and in order to create a mapped address
you'll need to allocate storage space on the stack to hold it. New code
would be:
sin6 = &sin6_storage;
ipv6_addr_set(&sin6->sin6_addr, 0, 0, htonl(0x0000FFFF),
sin->sin_addr);
gcc really should have complained about that...
Maybe in the future rq_addr can just be in the correct form, but there's
a lot of other code that would need to change for that.
-Brian
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2007-09-06 16:17 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-09 7:22 [PATCH 1/1] NFS: change the ip_map cache code to handle IPv6 addresses Aurélien Charbon
2007-08-09 12:16 ` Chuck Lever
2007-08-09 15:08 ` Aurélien Charbon
2007-08-09 15:14 ` Chuck Lever
2007-08-10 1:11 ` Neil Brown
2007-08-10 1:06 ` Neil Brown
-- strict thread matches above, loose matches on Subject: below --
2007-08-23 13:18 Aurélien Charbon
2007-08-23 15:32 ` Brian Haley
2007-09-06 11:30 ` Aurélien Charbon
2007-09-06 16:16 ` Brian Haley
2007-08-23 15:39 ` Chuck Lever
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).