NFS: change the ip_map cache code to handle IPv6 addresses
Subsystems (5)
PATCH 1/1 NFS: change the ip_map cache code to handle IPv6 addresses
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.
---
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(-)
fs/nfsd/export.c 2007-08-23 13:51:08.000000000 +0200 renamed from fs/nfsd/export.c 2007-08-23 13:18:16.000000000 +0200 +0 -0
@@ -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);fs/nfsd/nfsctl.c 2007-08-23 13:25:28.000000000 +0200 renamed from fs/nfsd/nfsctl.c 2007-08-23 13:18:16.000000000 +0200 +9 -2
@@ -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);include/linux/sunrpc/svcauth.h 2007-08-23 13:25:28.000000000 +0200 renamed from include/linux/sunrpc/svcauth.h 2007-08-23 13:18:21.000000000 +0200 +0 -0
@@ -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 *);
include/net/ipv6.h 2007-08-23 13:25:28.000000000 +0200 renamed from include/net/ipv6.h 2007-08-23 13:18:23.000000000 +0200 +0 -0
@@ -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
net/sunrpc/svcauth_unix.c 2007-08-23 13:52:02.000000000 +0200 renamed from net/sunrpc/svcauth_unix.c 2007-08-23 13:18:24.000000000 +0200 +0 -0
@@ -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 intsvcauth_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;Signature · 7 lines
********************************
Aurelien Charbon
Linux NFSv4 team
Bull SAS
Echirolles - France
http://nfsv4.bullopensource.org/
********************************Hi Aurelien,
Quoted 1 line · Aurélien Charbon
According to Neil's comments, I have tried to correct the mistakes of my first sending
I have some more comments.
Review exp_addclient(struct nfsctl_client *ncp) · line 1563
Quoted 5 lines
(quoted diff) +1
-0@@ -1559,6 +1560,7 @@ exp_addclient(struct nfsctl_client *ncp) { struct auth_domain *dom; int i, err; + struct in6_addr addr6;
Indentation looks wrong.
fs/nfsd/nfsctl.c 2007-08-23 13:25:28.000000000 +0200 static ssize_t write_getfs(struct file * · line 225
Quoted 11 lines
diff -p -u -r -N
linux-2.6.23-rc3/fs/nfsd/nfsctl.clinux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/nfsctl.c
---linux-2.6.23-rc3/fs/nfsd/nfsctl.c2007-08-23 13:18:16.000000000
+0200
+++linux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/nfsctl.c2007-08-23
13:25:28.000000000 +0200fs/nfsd/nfsctl.c 2007-08-23 13:25:28.000000000 +0200 renamed from fs/nfsd/nfsctl.c 2007-08-23 13:18:16.000000000 +0200 +1
-1@@ -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.
Quoted 4 lines
fs/nfsd/nfsctl.c 2007-08-23 13:25:28.000000000 +0200 renamed from fs/nfsd/nfsctl.c 2007-08-23 13:18:16.000000000 +0200 +0
-0if (size < sizeof(*data)) return -EINVAL; data = (struct nfsctl_fsparm*)buf;
fs/nfsd/nfsctl.c 2007-08-23 13:25:28.000000000 +0200 static ssize_t write_getfs(struct file * · line 244
Quoted 10 lines
fs/nfsd/nfsctl.c 2007-08-23 13:25:28.000000000 +0200 renamed from fs/nfsd/nfsctl.c 2007-08-23 13:18:16.000000000 +0200 +6
-1@@ -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?
Review static ssize_t write_getfd(struct file * · line 263
Quoted 5 lines
(quoted diff) +1
-0@@ -253,6 +260,7 @@ static ssize_t write_getfd(struct file * { struct nfsctl_fdparm *data; struct sockaddr_in *sin; + struct in6_addr in6;
Indentation.
fs/nfsd/nfsctl.c 2007-08-23 13:25:28.000000000 +0200 static ssize_t write_getfd(struct file * · line 287
Quoted 11 lines
fs/nfsd/nfsctl.c 2007-08-23 13:25:28.000000000 +0200 renamed from fs/nfsd/nfsctl.c 2007-08-23 13:18:16.000000000 +0200 +6
-1@@ -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?
Quoted 14 lines
diff -p -u -r -N
linux-2.6.23-rc3/include/net/ipv6.hlinux-2.6.23-rc3-IPv6-ipmap-cache/include/net/ipv6.h
---linux-2.6.23-rc3/include/net/ipv6.h2007-08-23 13:18:23.000000000
+0200
+++linux-2.6.23-rc3-IPv6-ipmap-cache/include/net/ipv6.h2007-08-23
13:25:28.000000000 +0200(quoted diff) +1
-0@@ -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
Review DECLARE_SNMP_STAT(struct udp_mib, udplit · line 176
Quoted 9 lines
(quoted diff) +5
-0@@ -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?
Review DECLARE_SNMP_STAT(struct udp_mib, udplit
Quoted 10 lines
(quoted diff) +9
-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; +}
This can be void, noone ever checks the return status. Maybe change the name to ipv6_addr_v4map() too?
Review static void svcauth_unix_domain_release( · line 88
Quoted 6 lines
(quoted diff) +1
-1@@ -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.
Review static void ip_map_init(struct cache_hea · line 136
Quoted 8 lines
(quoted diff) +1
-1static 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().
Quoted 11 lines
(quoted diff) +0
-7@@ -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);
Review static void ip_map_request(struct cache_ · line 171
Quoted 10 lines
(quoted diff) +9
-0+ 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.
Review static int ip_map_parse(struct cache_det · line 192
Quoted 12 lines
(quoted diff) +2
-2static 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.
Review static int ip_map_show(struct seq_file * · line 265
Quoted 6 lines
(quoted diff) +1
-1@@ -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.
Review static int ip_map_show(struct seq_file * · line 274
Quoted 7 lines
(quoted diff) +1
-1if (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()
Quoted 18 lines
(quoted diff) +10
-8- 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",
Review static int ip_map_show(struct seq_file * · line 294
Quoted 10 lines
(quoted diff) +10
-0+ 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]?
Review static int ip_map_show(struct seq_file * · line 301
Quoted 9 lines
(quoted diff) +2
-2-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
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)
---
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(-)
fs/nfsd/export.c +0 -0
@@ -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);
fs/nfsd/nfsctl.c +0 -0
@@ -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);include/linux/sunrpc/svcauth.h +0 -0
@@ -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 *);
include/net/ipv6.h +0 -0
@@ -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 && net/sunrpc/svcauth_unix.c +0 -0
@@ -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 intsvcauth_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;
Signature · 7 lines
********************************
Aurelien Charbon
Linux NFSv4 team
Bull SAS
Echirolles - France
http://nfsv4.bullopensource.org/
********************************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.
---
fs/nfsd/export.c +7 -3
@@ -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);
fs/nfsd/nfsctl.c +13 -3
@@ -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 );
include/linux/sunrpc/svcauth.h +2 -2
@@ -120,10 +120,10 @@ extern void svc_auth_unregister(rpc_authextern 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 *);
include/net/ipv6.h +15 -0
@@ -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, udplitif (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 &&
net/sunrpc/svcauth_unix.c +76 -36
235 lines not on this page · raw message
Hi Aurelien,
More comments.
fs/nfsd/export.c exp_addclient(struct nfsctl_client *ncp) · line 1584
Quoted 10 lines · Aurélien Charbon
This is a small part of missing pieces of IPv6 support for the server. It deals with the
ip_mapcaching code part.fs/nfsd/export.c +3
-3/* 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.
fs/nfsd/nfsctl.c static ssize_t write_getfs(struct file * · line 242
Quoted 8 lines
fs/nfsd/nfsctl.c +3
-1@@ -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.
fs/nfsd/nfsctl.c static ssize_t write_getfd(struct file * · line 282
Quoted 8 lines
fs/nfsd/nfsctl.c +3
-1@@ -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.
include/net/ipv6.h DECLARE_SNMP_STAT(struct udp_mib, udplit · line 175
Quoted 5 lines
include/net/ipv6.h +5
-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)))
Can go away, right?
include/net/ipv6.h static inline int ipv6_addr_any(const st · line 393
Quoted 7 lines
include/net/ipv6.h +7
-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; +}
This can go away. Looking at other code that does this - TCP, UDP, DCCP, they just call ipv6_addr_set() directly.
net/sunrpc/svcauth_unix.c static inline int hash_ip(__be32 ip) · line 122
Quoted 7 lines
net/sunrpc/svcauth_unix.c +7
-0+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.
net/sunrpc/svcauth_unix.c static void ip_map_request(struct cache_ · line 160
Quoted 3 lines
net/sunrpc/svcauth_unix.c +0
-0@@ -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.
net/sunrpc/svcauth_unix.c static void ip_map_request(struct cache_ · line 171
Quoted 9 lines
net/sunrpc/svcauth_unix.c +9
-0+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 -------------------------------^^
net/sunrpc/svcauth_unix.c struct cache_detail ip_map_cache = { · line 311
Quoted 2 lines
net/sunrpc/svcauth_unix.c +1
-1-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.
net/sunrpc/svcauth_unix.c static int ip_map_update(struct ip_map * · line 356
Quoted 2 lines
net/sunrpc/svcauth_unix.c +1
-1-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.
net/sunrpc/svcauth_unix.c int auth_unix_forget_old(struct auth_dom · line 383
Quoted 2 lines
net/sunrpc/svcauth_unix.c +1
-1-struct auth_domain *auth_unix_lookup (struct in_addr addr) +struct auth_domain *auth_unix_lookup (struct in6_addr addr)
Here too.
net/sunrpc/svcauth_unix.c static int unix_gid_find(uid_t uid, stru · line 673
Quoted 7 lines
net/sunrpc/svcauth_unix.c +2
-1@@ -641,7 +669,19 @@ static int unix_gid_find(uid_t uid, struint 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:
Review static int unix_gid_find(uid_t uid, stru · line 674
Quoted 1 line
(quoted diff) +1
-0+ struct sockaddr_in6 *sin6, sin6_storage;
See below.
net/sunrpc/svcauth_unix.c static int unix_gid_find(uid_t uid, stru · line 680
Quoted 7 lines
net/sunrpc/svcauth_unix.c +7
-0+ +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
Hi Aurélien-
Quoted 94 lines · Aurélien Charbon
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_mapcaching code part.It changes the
ip_mapstructure 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 <[email protected]>---
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.clinux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/export.cfs/nfsd/export.c 2007-08-23 renamed from fs/nfsd/export.c 2007-08-23 13:18:16.000000000 +0200 +0
-013:51:08.000000000 +0200
fs/nfsd/export.c 2007-08-23 renamed from fs/nfsd/export.c 2007-08-23 13:18:16.000000000 +0200 +7
-3@@ -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.clinux-2.6.23-rc3-IPv6-ipmap-cache/fs/nfsd/nfsctl.cfs/nfsd/nfsctl.c 2007-08-23 renamed from fs/nfsd/nfsctl.c 2007-08-23 13:18:16.000000000 +0200 +0
-013:25:28.000000000 +0200
fs/nfsd/nfsctl.c 2007-08-23 renamed from fs/nfsd/nfsctl.c 2007-08-23 13:18:16.000000000 +0200 +10
-2@@ -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;
fs/nfsd/nfsctl.c 2007-08-23 static ssize_t write_getfd(struct file * · line 287
Quoted 10 lines
fs/nfsd/nfsctl.c 2007-08-23 renamed from fs/nfsd/nfsctl.c 2007-08-23 13:18:16.000000000 +0200 +6
-1@@ -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.
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