diff options
author | Aleksey Senin <alekseys@voltaire.com> | 2008-12-24 13:16:37 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-12-24 13:16:37 -0500 |
commit | 38617c64bf9a10bf20e41d95b69bb81e8560fe9d (patch) | |
tree | c8ecf25f528bae1320c21d09eb61edb956f6d438 /drivers/infiniband/core | |
parent | 061e41fdb5047b1fb161e89664057835935ca1d2 (diff) |
RDMA/addr: Add support for translating IPv6 addresses
Add support for translating AF_INET6 addresses to the IB address
translation service. This requires using struct sockaddr_storage
instead of struct sockaddr wherever an IPv6 address might be stored,
and adding cases to handle IPv6 in addition to IPv4 to the various
translation functions.
Signed-off-by: Aleksey Senin <aleksey@alst60.(none)>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/core')
-rw-r--r-- | drivers/infiniband/core/addr.c | 196 |
1 files changed, 151 insertions, 45 deletions
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 09a2bec7fd32..d98b05b28262 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c | |||
@@ -41,6 +41,8 @@ | |||
41 | #include <net/neighbour.h> | 41 | #include <net/neighbour.h> |
42 | #include <net/route.h> | 42 | #include <net/route.h> |
43 | #include <net/netevent.h> | 43 | #include <net/netevent.h> |
44 | #include <net/addrconf.h> | ||
45 | #include <net/ip6_route.h> | ||
44 | #include <rdma/ib_addr.h> | 46 | #include <rdma/ib_addr.h> |
45 | 47 | ||
46 | MODULE_AUTHOR("Sean Hefty"); | 48 | MODULE_AUTHOR("Sean Hefty"); |
@@ -49,8 +51,8 @@ MODULE_LICENSE("Dual BSD/GPL"); | |||
49 | 51 | ||
50 | struct addr_req { | 52 | struct addr_req { |
51 | struct list_head list; | 53 | struct list_head list; |
52 | struct sockaddr src_addr; | 54 | struct sockaddr_storage src_addr; |
53 | struct sockaddr dst_addr; | 55 | struct sockaddr_storage dst_addr; |
54 | struct rdma_dev_addr *addr; | 56 | struct rdma_dev_addr *addr; |
55 | struct rdma_addr_client *client; | 57 | struct rdma_addr_client *client; |
56 | void *context; | 58 | void *context; |
@@ -113,15 +115,32 @@ EXPORT_SYMBOL(rdma_copy_addr); | |||
113 | int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) | 115 | int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) |
114 | { | 116 | { |
115 | struct net_device *dev; | 117 | struct net_device *dev; |
116 | __be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr; | 118 | int ret = -EADDRNOTAVAIL; |
117 | int ret; | ||
118 | 119 | ||
119 | dev = ip_dev_find(&init_net, ip); | 120 | switch (addr->sa_family) { |
120 | if (!dev) | 121 | case AF_INET: |
121 | return -EADDRNOTAVAIL; | 122 | dev = ip_dev_find(&init_net, |
123 | ((struct sockaddr_in *) addr)->sin_addr.s_addr); | ||
124 | |||
125 | if (!dev) | ||
126 | return ret; | ||
122 | 127 | ||
123 | ret = rdma_copy_addr(dev_addr, dev, NULL); | 128 | ret = rdma_copy_addr(dev_addr, dev, NULL); |
124 | dev_put(dev); | 129 | dev_put(dev); |
130 | break; | ||
131 | case AF_INET6: | ||
132 | for_each_netdev(&init_net, dev) { | ||
133 | if (ipv6_chk_addr(&init_net, | ||
134 | &((struct sockaddr_in6 *) addr)->sin6_addr, | ||
135 | dev, 1)) { | ||
136 | ret = rdma_copy_addr(dev_addr, dev, NULL); | ||
137 | break; | ||
138 | } | ||
139 | } | ||
140 | break; | ||
141 | default: | ||
142 | break; | ||
143 | } | ||
125 | return ret; | 144 | return ret; |
126 | } | 145 | } |
127 | EXPORT_SYMBOL(rdma_translate_ip); | 146 | EXPORT_SYMBOL(rdma_translate_ip); |
@@ -156,22 +175,37 @@ static void queue_req(struct addr_req *req) | |||
156 | mutex_unlock(&lock); | 175 | mutex_unlock(&lock); |
157 | } | 176 | } |
158 | 177 | ||
159 | static void addr_send_arp(struct sockaddr_in *dst_in) | 178 | static void addr_send_arp(struct sockaddr *dst_in) |
160 | { | 179 | { |
161 | struct rtable *rt; | 180 | struct rtable *rt; |
162 | struct flowi fl; | 181 | struct flowi fl; |
163 | __be32 dst_ip = dst_in->sin_addr.s_addr; | 182 | struct dst_entry *dst; |
164 | 183 | ||
165 | memset(&fl, 0, sizeof fl); | 184 | memset(&fl, 0, sizeof fl); |
166 | fl.nl_u.ip4_u.daddr = dst_ip; | 185 | if (dst_in->sa_family == AF_INET) { |
167 | if (ip_route_output_key(&init_net, &rt, &fl)) | 186 | fl.nl_u.ip4_u.daddr = |
168 | return; | 187 | ((struct sockaddr_in *) dst_in)->sin_addr.s_addr; |
169 | 188 | ||
170 | neigh_event_send(rt->u.dst.neighbour, NULL); | 189 | if (ip_route_output_key(&init_net, &rt, &fl)) |
171 | ip_rt_put(rt); | 190 | return; |
191 | |||
192 | neigh_event_send(rt->u.dst.neighbour, NULL); | ||
193 | ip_rt_put(rt); | ||
194 | |||
195 | } else { | ||
196 | fl.nl_u.ip6_u.daddr = | ||
197 | ((struct sockaddr_in6 *) dst_in)->sin6_addr; | ||
198 | |||
199 | dst = ip6_route_output(&init_net, NULL, &fl); | ||
200 | if (!dst) | ||
201 | return; | ||
202 | |||
203 | neigh_event_send(dst->neighbour, NULL); | ||
204 | dst_release(dst); | ||
205 | } | ||
172 | } | 206 | } |
173 | 207 | ||
174 | static int addr_resolve_remote(struct sockaddr_in *src_in, | 208 | static int addr4_resolve_remote(struct sockaddr_in *src_in, |
175 | struct sockaddr_in *dst_in, | 209 | struct sockaddr_in *dst_in, |
176 | struct rdma_dev_addr *addr) | 210 | struct rdma_dev_addr *addr) |
177 | { | 211 | { |
@@ -220,10 +254,51 @@ out: | |||
220 | return ret; | 254 | return ret; |
221 | } | 255 | } |
222 | 256 | ||
257 | static int addr6_resolve_remote(struct sockaddr_in6 *src_in, | ||
258 | struct sockaddr_in6 *dst_in, | ||
259 | struct rdma_dev_addr *addr) | ||
260 | { | ||
261 | struct flowi fl; | ||
262 | struct neighbour *neigh; | ||
263 | struct dst_entry *dst; | ||
264 | int ret = -ENODATA; | ||
265 | |||
266 | memset(&fl, 0, sizeof fl); | ||
267 | fl.nl_u.ip6_u.daddr = dst_in->sin6_addr; | ||
268 | fl.nl_u.ip6_u.saddr = src_in->sin6_addr; | ||
269 | |||
270 | dst = ip6_route_output(&init_net, NULL, &fl); | ||
271 | if (!dst) | ||
272 | return ret; | ||
273 | |||
274 | if (dst->dev->flags & IFF_NOARP) { | ||
275 | ret = rdma_copy_addr(addr, dst->dev, NULL); | ||
276 | } else { | ||
277 | neigh = dst->neighbour; | ||
278 | if (neigh && (neigh->nud_state & NUD_VALID)) | ||
279 | ret = rdma_copy_addr(addr, neigh->dev, neigh->ha); | ||
280 | } | ||
281 | |||
282 | dst_release(dst); | ||
283 | return ret; | ||
284 | } | ||
285 | |||
286 | static int addr_resolve_remote(struct sockaddr *src_in, | ||
287 | struct sockaddr *dst_in, | ||
288 | struct rdma_dev_addr *addr) | ||
289 | { | ||
290 | if (src_in->sa_family == AF_INET) { | ||
291 | return addr4_resolve_remote((struct sockaddr_in *) src_in, | ||
292 | (struct sockaddr_in *) dst_in, addr); | ||
293 | } else | ||
294 | return addr6_resolve_remote((struct sockaddr_in6 *) src_in, | ||
295 | (struct sockaddr_in6 *) dst_in, addr); | ||
296 | } | ||
297 | |||
223 | static void process_req(struct work_struct *work) | 298 | static void process_req(struct work_struct *work) |
224 | { | 299 | { |
225 | struct addr_req *req, *temp_req; | 300 | struct addr_req *req, *temp_req; |
226 | struct sockaddr_in *src_in, *dst_in; | 301 | struct sockaddr *src_in, *dst_in; |
227 | struct list_head done_list; | 302 | struct list_head done_list; |
228 | 303 | ||
229 | INIT_LIST_HEAD(&done_list); | 304 | INIT_LIST_HEAD(&done_list); |
@@ -231,8 +306,8 @@ static void process_req(struct work_struct *work) | |||
231 | mutex_lock(&lock); | 306 | mutex_lock(&lock); |
232 | list_for_each_entry_safe(req, temp_req, &req_list, list) { | 307 | list_for_each_entry_safe(req, temp_req, &req_list, list) { |
233 | if (req->status == -ENODATA) { | 308 | if (req->status == -ENODATA) { |
234 | src_in = (struct sockaddr_in *) &req->src_addr; | 309 | src_in = (struct sockaddr *) &req->src_addr; |
235 | dst_in = (struct sockaddr_in *) &req->dst_addr; | 310 | dst_in = (struct sockaddr *) &req->dst_addr; |
236 | req->status = addr_resolve_remote(src_in, dst_in, | 311 | req->status = addr_resolve_remote(src_in, dst_in, |
237 | req->addr); | 312 | req->addr); |
238 | if (req->status && time_after_eq(jiffies, req->timeout)) | 313 | if (req->status && time_after_eq(jiffies, req->timeout)) |
@@ -251,41 +326,72 @@ static void process_req(struct work_struct *work) | |||
251 | 326 | ||
252 | list_for_each_entry_safe(req, temp_req, &done_list, list) { | 327 | list_for_each_entry_safe(req, temp_req, &done_list, list) { |
253 | list_del(&req->list); | 328 | list_del(&req->list); |
254 | req->callback(req->status, &req->src_addr, req->addr, | 329 | req->callback(req->status, (struct sockaddr *) &req->src_addr, |
255 | req->context); | 330 | req->addr, req->context); |
256 | put_client(req->client); | 331 | put_client(req->client); |
257 | kfree(req); | 332 | kfree(req); |
258 | } | 333 | } |
259 | } | 334 | } |
260 | 335 | ||
261 | static int addr_resolve_local(struct sockaddr_in *src_in, | 336 | static int addr_resolve_local(struct sockaddr *src_in, |
262 | struct sockaddr_in *dst_in, | 337 | struct sockaddr *dst_in, |
263 | struct rdma_dev_addr *addr) | 338 | struct rdma_dev_addr *addr) |
264 | { | 339 | { |
265 | struct net_device *dev; | 340 | struct net_device *dev; |
266 | __be32 src_ip = src_in->sin_addr.s_addr; | ||
267 | __be32 dst_ip = dst_in->sin_addr.s_addr; | ||
268 | int ret; | 341 | int ret; |
269 | 342 | ||
270 | dev = ip_dev_find(&init_net, dst_ip); | 343 | if (dst_in->sa_family == AF_INET) { |
271 | if (!dev) | 344 | __be32 src_ip = ((struct sockaddr_in *) src_in)->sin_addr.s_addr; |
272 | return -EADDRNOTAVAIL; | 345 | __be32 dst_ip = ((struct sockaddr_in *) dst_in)->sin_addr.s_addr; |
273 | 346 | ||
274 | if (ipv4_is_zeronet(src_ip)) { | 347 | dev = ip_dev_find(&init_net, dst_ip); |
275 | src_in->sin_family = dst_in->sin_family; | 348 | if (!dev) |
276 | src_in->sin_addr.s_addr = dst_ip; | 349 | return -EADDRNOTAVAIL; |
277 | ret = rdma_copy_addr(addr, dev, dev->dev_addr); | 350 | |
278 | } else if (ipv4_is_loopback(src_ip)) { | 351 | if (ipv4_is_zeronet(src_ip)) { |
279 | ret = rdma_translate_ip((struct sockaddr *)dst_in, addr); | 352 | src_in->sa_family = dst_in->sa_family; |
280 | if (!ret) | 353 | ((struct sockaddr_in *) src_in)->sin_addr.s_addr = dst_ip; |
281 | memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); | 354 | ret = rdma_copy_addr(addr, dev, dev->dev_addr); |
355 | } else if (ipv4_is_loopback(src_ip)) { | ||
356 | ret = rdma_translate_ip(dst_in, addr); | ||
357 | if (!ret) | ||
358 | memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); | ||
359 | } else { | ||
360 | ret = rdma_translate_ip(src_in, addr); | ||
361 | if (!ret) | ||
362 | memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); | ||
363 | } | ||
364 | dev_put(dev); | ||
282 | } else { | 365 | } else { |
283 | ret = rdma_translate_ip((struct sockaddr *)src_in, addr); | 366 | struct in6_addr *a; |
284 | if (!ret) | 367 | |
285 | memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); | 368 | for_each_netdev(&init_net, dev) |
369 | if (ipv6_chk_addr(&init_net, | ||
370 | &((struct sockaddr_in6 *) addr)->sin6_addr, | ||
371 | dev, 1)) | ||
372 | break; | ||
373 | |||
374 | if (!dev) | ||
375 | return -EADDRNOTAVAIL; | ||
376 | |||
377 | a = &((struct sockaddr_in6 *) src_in)->sin6_addr; | ||
378 | |||
379 | if (ipv6_addr_any(a)) { | ||
380 | src_in->sa_family = dst_in->sa_family; | ||
381 | ((struct sockaddr_in6 *) src_in)->sin6_addr = | ||
382 | ((struct sockaddr_in6 *) dst_in)->sin6_addr; | ||
383 | ret = rdma_copy_addr(addr, dev, dev->dev_addr); | ||
384 | } else if (ipv6_addr_loopback(a)) { | ||
385 | ret = rdma_translate_ip(dst_in, addr); | ||
386 | if (!ret) | ||
387 | memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); | ||
388 | } else { | ||
389 | ret = rdma_translate_ip(src_in, addr); | ||
390 | if (!ret) | ||
391 | memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); | ||
392 | } | ||
286 | } | 393 | } |
287 | 394 | ||
288 | dev_put(dev); | ||
289 | return ret; | 395 | return ret; |
290 | } | 396 | } |
291 | 397 | ||
@@ -296,7 +402,7 @@ int rdma_resolve_ip(struct rdma_addr_client *client, | |||
296 | struct rdma_dev_addr *addr, void *context), | 402 | struct rdma_dev_addr *addr, void *context), |
297 | void *context) | 403 | void *context) |
298 | { | 404 | { |
299 | struct sockaddr_in *src_in, *dst_in; | 405 | struct sockaddr *src_in, *dst_in; |
300 | struct addr_req *req; | 406 | struct addr_req *req; |
301 | int ret = 0; | 407 | int ret = 0; |
302 | 408 | ||
@@ -313,8 +419,8 @@ int rdma_resolve_ip(struct rdma_addr_client *client, | |||
313 | req->client = client; | 419 | req->client = client; |
314 | atomic_inc(&client->refcount); | 420 | atomic_inc(&client->refcount); |
315 | 421 | ||
316 | src_in = (struct sockaddr_in *) &req->src_addr; | 422 | src_in = (struct sockaddr *) &req->src_addr; |
317 | dst_in = (struct sockaddr_in *) &req->dst_addr; | 423 | dst_in = (struct sockaddr *) &req->dst_addr; |
318 | 424 | ||
319 | req->status = addr_resolve_local(src_in, dst_in, addr); | 425 | req->status = addr_resolve_local(src_in, dst_in, addr); |
320 | if (req->status == -EADDRNOTAVAIL) | 426 | if (req->status == -EADDRNOTAVAIL) |