aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorAurélien Charbon <aurelien.charbon@ext.bull.net>2008-01-18 09:50:56 -0500
committerJ. Bruce Fields <bfields@citi.umich.edu>2008-04-23 16:13:36 -0400
commitf15364bd4cf8799a7677b6daeed7b67d9139d974 (patch)
treebef48016533d184ea171d4b64336a5ad65ebc18e /net
parentd751a7cd0695554498f25d3026ca6710dbb3698f (diff)
IPv6 support for NFS server export caches
This adds IPv6 support to the interfaces that are used to express nfsd exports. All addressed are stored internally as IPv6; backwards compatibility is maintained using mapped addresses. Thanks to Bruce Fields, Brian Haley, Neil Brown and Hideaki Joshifuji for comments Signed-off-by: Aurelien Charbon <aurelien.charbon@bull.net> Cc: Neil Brown <neilb@suse.de> Cc: Brian Haley <brian.haley@hp.com> Cc: YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/svcauth_unix.c118
1 files changed, 80 insertions, 38 deletions
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 3c64051e4555..3f30ee6006ae 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -11,7 +11,8 @@
11#include <linux/hash.h> 11#include <linux/hash.h>
12#include <linux/string.h> 12#include <linux/string.h>
13#include <net/sock.h> 13#include <net/sock.h>
14 14#include <net/ipv6.h>
15#include <linux/kernel.h>
15#define RPCDBG_FACILITY RPCDBG_AUTH 16#define RPCDBG_FACILITY RPCDBG_AUTH
16 17
17 18
@@ -85,7 +86,7 @@ static void svcauth_unix_domain_release(struct auth_domain *dom)
85struct ip_map { 86struct ip_map {
86 struct cache_head h; 87 struct cache_head h;
87 char m_class[8]; /* e.g. "nfsd" */ 88 char m_class[8]; /* e.g. "nfsd" */
88 struct in_addr m_addr; 89 struct in6_addr m_addr;
89 struct unix_domain *m_client; 90 struct unix_domain *m_client;
90 int m_add_change; 91 int m_add_change;
91}; 92};
@@ -113,12 +114,19 @@ static inline int hash_ip(__be32 ip)
113 return (hash ^ (hash>>8)) & 0xff; 114 return (hash ^ (hash>>8)) & 0xff;
114} 115}
115#endif 116#endif
117static inline int hash_ip6(struct in6_addr ip)
118{
119 return (hash_ip(ip.s6_addr32[0]) ^
120 hash_ip(ip.s6_addr32[1]) ^
121 hash_ip(ip.s6_addr32[2]) ^
122 hash_ip(ip.s6_addr32[3]));
123}
116static int ip_map_match(struct cache_head *corig, struct cache_head *cnew) 124static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
117{ 125{
118 struct ip_map *orig = container_of(corig, struct ip_map, h); 126 struct ip_map *orig = container_of(corig, struct ip_map, h);
119 struct ip_map *new = container_of(cnew, struct ip_map, h); 127 struct ip_map *new = container_of(cnew, struct ip_map, h);
120 return strcmp(orig->m_class, new->m_class) == 0 128 return strcmp(orig->m_class, new->m_class) == 0
121 && orig->m_addr.s_addr == new->m_addr.s_addr; 129 && ipv6_addr_equal(&orig->m_addr, &new->m_addr);
122} 130}
123static void ip_map_init(struct cache_head *cnew, struct cache_head *citem) 131static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
124{ 132{
@@ -126,7 +134,7 @@ static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
126 struct ip_map *item = container_of(citem, struct ip_map, h); 134 struct ip_map *item = container_of(citem, struct ip_map, h);
127 135
128 strcpy(new->m_class, item->m_class); 136 strcpy(new->m_class, item->m_class);
129 new->m_addr.s_addr = item->m_addr.s_addr; 137 ipv6_addr_copy(&new->m_addr, &item->m_addr);
130} 138}
131static void update(struct cache_head *cnew, struct cache_head *citem) 139static void update(struct cache_head *cnew, struct cache_head *citem)
132{ 140{
@@ -150,22 +158,24 @@ static void ip_map_request(struct cache_detail *cd,
150 struct cache_head *h, 158 struct cache_head *h,
151 char **bpp, int *blen) 159 char **bpp, int *blen)
152{ 160{
153 char text_addr[20]; 161 char text_addr[40];
154 struct ip_map *im = container_of(h, struct ip_map, h); 162 struct ip_map *im = container_of(h, struct ip_map, h);
155 __be32 addr = im->m_addr.s_addr;
156
157 snprintf(text_addr, 20, "%u.%u.%u.%u",
158 ntohl(addr) >> 24 & 0xff,
159 ntohl(addr) >> 16 & 0xff,
160 ntohl(addr) >> 8 & 0xff,
161 ntohl(addr) >> 0 & 0xff);
162 163
164 if (ipv6_addr_v4mapped(&(im->m_addr))) {
165 snprintf(text_addr, 20, NIPQUAD_FMT,
166 ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
167 ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
168 ntohl(im->m_addr.s6_addr32[3]) >> 8 & 0xff,
169 ntohl(im->m_addr.s6_addr32[3]) >> 0 & 0xff);
170 } else {
171 snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
172 }
163 qword_add(bpp, blen, im->m_class); 173 qword_add(bpp, blen, im->m_class);
164 qword_add(bpp, blen, text_addr); 174 qword_add(bpp, blen, text_addr);
165 (*bpp)[-1] = '\n'; 175 (*bpp)[-1] = '\n';
166} 176}
167 177
168static struct ip_map *ip_map_lookup(char *class, struct in_addr addr); 178static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr);
169static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry); 179static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
170 180
171static int ip_map_parse(struct cache_detail *cd, 181static int ip_map_parse(struct cache_detail *cd,
@@ -176,10 +186,10 @@ static int ip_map_parse(struct cache_detail *cd,
176 * for scratch: */ 186 * for scratch: */
177 char *buf = mesg; 187 char *buf = mesg;
178 int len; 188 int len;
179 int b1,b2,b3,b4; 189 int b1, b2, b3, b4, b5, b6, b7, b8;
180 char c; 190 char c;
181 char class[8]; 191 char class[8];
182 struct in_addr addr; 192 struct in6_addr addr;
183 int err; 193 int err;
184 194
185 struct ip_map *ipmp; 195 struct ip_map *ipmp;
@@ -198,7 +208,23 @@ static int ip_map_parse(struct cache_detail *cd,
198 len = qword_get(&mesg, buf, mlen); 208 len = qword_get(&mesg, buf, mlen);
199 if (len <= 0) return -EINVAL; 209 if (len <= 0) return -EINVAL;
200 210
201 if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) 211 if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
212 addr.s6_addr32[0] = 0;
213 addr.s6_addr32[1] = 0;
214 addr.s6_addr32[2] = htonl(0xffff);
215 addr.s6_addr32[3] =
216 htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
217 } else if (sscanf(buf, NIP6_FMT "%c",
218 &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
219 addr.s6_addr16[0] = htons(b1);
220 addr.s6_addr16[1] = htons(b2);
221 addr.s6_addr16[2] = htons(b3);
222 addr.s6_addr16[3] = htons(b4);
223 addr.s6_addr16[4] = htons(b5);
224 addr.s6_addr16[5] = htons(b6);
225 addr.s6_addr16[6] = htons(b7);
226 addr.s6_addr16[7] = htons(b8);
227 } else
202 return -EINVAL; 228 return -EINVAL;
203 229
204 expiry = get_expiry(&mesg); 230 expiry = get_expiry(&mesg);
@@ -216,10 +242,7 @@ static int ip_map_parse(struct cache_detail *cd,
216 } else 242 } else
217 dom = NULL; 243 dom = NULL;
218 244
219 addr.s_addr = 245 ipmp = ip_map_lookup(class, &addr);
220 htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
221
222 ipmp = ip_map_lookup(class,addr);
223 if (ipmp) { 246 if (ipmp) {
224 err = ip_map_update(ipmp, 247 err = ip_map_update(ipmp,
225 container_of(dom, struct unix_domain, h), 248 container_of(dom, struct unix_domain, h),
@@ -239,7 +262,7 @@ static int ip_map_show(struct seq_file *m,
239 struct cache_head *h) 262 struct cache_head *h)
240{ 263{
241 struct ip_map *im; 264 struct ip_map *im;
242 struct in_addr addr; 265 struct in6_addr addr;
243 char *dom = "-no-domain-"; 266 char *dom = "-no-domain-";
244 267
245 if (h == NULL) { 268 if (h == NULL) {
@@ -248,20 +271,24 @@ static int ip_map_show(struct seq_file *m,
248 } 271 }
249 im = container_of(h, struct ip_map, h); 272 im = container_of(h, struct ip_map, h);
250 /* class addr domain */ 273 /* class addr domain */
251 addr = im->m_addr; 274 ipv6_addr_copy(&addr, &im->m_addr);
252 275
253 if (test_bit(CACHE_VALID, &h->flags) && 276 if (test_bit(CACHE_VALID, &h->flags) &&
254 !test_bit(CACHE_NEGATIVE, &h->flags)) 277 !test_bit(CACHE_NEGATIVE, &h->flags))
255 dom = im->m_client->h.name; 278 dom = im->m_client->h.name;
256 279
257 seq_printf(m, "%s %d.%d.%d.%d %s\n", 280 if (ipv6_addr_v4mapped(&addr)) {
258 im->m_class, 281 seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
259 ntohl(addr.s_addr) >> 24 & 0xff, 282 im->m_class,
260 ntohl(addr.s_addr) >> 16 & 0xff, 283 ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
261 ntohl(addr.s_addr) >> 8 & 0xff, 284 ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
262 ntohl(addr.s_addr) >> 0 & 0xff, 285 ntohl(addr.s6_addr32[3]) >> 8 & 0xff,
263 dom 286 ntohl(addr.s6_addr32[3]) >> 0 & 0xff,
264 ); 287 dom);
288 } else {
289 seq_printf(m, "%s" NIP6_FMT "%s\n",
290 im->m_class, NIP6(addr), dom);
291 }
265 return 0; 292 return 0;
266} 293}
267 294
@@ -281,16 +308,16 @@ struct cache_detail ip_map_cache = {
281 .alloc = ip_map_alloc, 308 .alloc = ip_map_alloc,
282}; 309};
283 310
284static struct ip_map *ip_map_lookup(char *class, struct in_addr addr) 311static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
285{ 312{
286 struct ip_map ip; 313 struct ip_map ip;
287 struct cache_head *ch; 314 struct cache_head *ch;
288 315
289 strcpy(ip.m_class, class); 316 strcpy(ip.m_class, class);
290 ip.m_addr = addr; 317 ipv6_addr_copy(&ip.m_addr, addr);
291 ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h, 318 ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
292 hash_str(class, IP_HASHBITS) ^ 319 hash_str(class, IP_HASHBITS) ^
293 hash_ip(addr.s_addr)); 320 hash_ip6(*addr));
294 321
295 if (ch) 322 if (ch)
296 return container_of(ch, struct ip_map, h); 323 return container_of(ch, struct ip_map, h);
@@ -319,14 +346,14 @@ static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t ex
319 ch = sunrpc_cache_update(&ip_map_cache, 346 ch = sunrpc_cache_update(&ip_map_cache,
320 &ip.h, &ipm->h, 347 &ip.h, &ipm->h,
321 hash_str(ipm->m_class, IP_HASHBITS) ^ 348 hash_str(ipm->m_class, IP_HASHBITS) ^
322 hash_ip(ipm->m_addr.s_addr)); 349 hash_ip6(ipm->m_addr));
323 if (!ch) 350 if (!ch)
324 return -ENOMEM; 351 return -ENOMEM;
325 cache_put(ch, &ip_map_cache); 352 cache_put(ch, &ip_map_cache);
326 return 0; 353 return 0;
327} 354}
328 355
329int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom) 356int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
330{ 357{
331 struct unix_domain *udom; 358 struct unix_domain *udom;
332 struct ip_map *ipmp; 359 struct ip_map *ipmp;
@@ -355,7 +382,7 @@ int auth_unix_forget_old(struct auth_domain *dom)
355} 382}
356EXPORT_SYMBOL(auth_unix_forget_old); 383EXPORT_SYMBOL(auth_unix_forget_old);
357 384
358struct auth_domain *auth_unix_lookup(struct in_addr addr) 385struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
359{ 386{
360 struct ip_map *ipm; 387 struct ip_map *ipm;
361 struct auth_domain *rv; 388 struct auth_domain *rv;
@@ -650,9 +677,24 @@ static int unix_gid_find(uid_t uid, struct group_info **gip,
650int 677int
651svcauth_unix_set_client(struct svc_rqst *rqstp) 678svcauth_unix_set_client(struct svc_rqst *rqstp)
652{ 679{
653 struct sockaddr_in *sin = svc_addr_in(rqstp); 680 struct sockaddr_in *sin;
681 struct sockaddr_in6 *sin6, sin6_storage;
654 struct ip_map *ipm; 682 struct ip_map *ipm;
655 683
684 switch (rqstp->rq_addr.ss_family) {
685 case AF_INET:
686 sin = svc_addr_in(rqstp);
687 sin6 = &sin6_storage;
688 ipv6_addr_set(&sin6->sin6_addr, 0, 0,
689 htonl(0x0000FFFF), sin->sin_addr.s_addr);
690 break;
691 case AF_INET6:
692 sin6 = svc_addr_in6(rqstp);
693 break;
694 default:
695 BUG();
696 }
697
656 rqstp->rq_client = NULL; 698 rqstp->rq_client = NULL;
657 if (rqstp->rq_proc == 0) 699 if (rqstp->rq_proc == 0)
658 return SVC_OK; 700 return SVC_OK;
@@ -660,7 +702,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
660 ipm = ip_map_cached_get(rqstp); 702 ipm = ip_map_cached_get(rqstp);
661 if (ipm == NULL) 703 if (ipm == NULL)
662 ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class, 704 ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
663 sin->sin_addr); 705 &sin6->sin6_addr);
664 706
665 if (ipm == NULL) 707 if (ipm == NULL)
666 return SVC_DENIED; 708 return SVC_DENIED;