aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSean Hefty <sean.hefty@intel.com>2009-11-19 19:46:25 -0500
committerRoland Dreier <rolandd@cisco.com>2009-11-19 19:46:25 -0500
commitd14714df61681cfecf945a58436edf197327e87f (patch)
tree1dc232e98f17c531d75b0646ea519264e49a63b1 /drivers
parent923c100ef019bf15fb89b6fa3d3ad0485d25d59b (diff)
IB/addr: Fix IPv6 routing lookup
Include link scope as part of address resolution. Combine local and remote address resolution into a single, simpler code path. Fix error checking in the IPv6 routing lookups. Based on work from: David Wilder <dwilder@us.ibm.com> Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Signed-off-by: Sean Hefty <sean.hefty@intel.com> [ Fix up cma_check_linklocal() for !IPV6 case. - Roland ] Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/infiniband/core/addr.c144
-rw-r--r--drivers/infiniband/core/cma.c47
2 files changed, 74 insertions, 117 deletions
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 38a7184ea745..abbb06996f9e 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -176,34 +176,6 @@ static void queue_req(struct addr_req *req)
176 mutex_unlock(&lock); 176 mutex_unlock(&lock);
177} 177}
178 178
179static void addr_send_arp(struct sockaddr *dst_in)
180{
181 struct rtable *rt;
182 struct flowi fl;
183
184 memset(&fl, 0, sizeof fl);
185
186 switch (dst_in->sa_family) {
187#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
188 case AF_INET6:
189 {
190 struct dst_entry *dst;
191
192 fl.nl_u.ip6_u.daddr =
193 ((struct sockaddr_in6 *) dst_in)->sin6_addr;
194
195 dst = ip6_route_output(&init_net, NULL, &fl);
196 if (!dst)
197 return;
198
199 neigh_event_send(dst->neighbour, NULL);
200 dst_release(dst);
201 break;
202 }
203#endif
204 }
205}
206
207static int addr4_resolve(struct sockaddr_in *src_in, 179static int addr4_resolve(struct sockaddr_in *src_in,
208 struct sockaddr_in *dst_in, 180 struct sockaddr_in *dst_in,
209 struct rdma_dev_addr *addr) 181 struct rdma_dev_addr *addr)
@@ -259,39 +231,63 @@ out:
259} 231}
260 232
261#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 233#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
262static int addr6_resolve_remote(struct sockaddr_in6 *src_in, 234static int addr6_resolve(struct sockaddr_in6 *src_in,
263 struct sockaddr_in6 *dst_in, 235 struct sockaddr_in6 *dst_in,
264 struct rdma_dev_addr *addr) 236 struct rdma_dev_addr *addr)
265{ 237{
266 struct flowi fl; 238 struct flowi fl;
267 struct neighbour *neigh; 239 struct neighbour *neigh;
268 struct dst_entry *dst; 240 struct dst_entry *dst;
269 int ret = -ENODATA; 241 int ret;
270 242
271 memset(&fl, 0, sizeof fl); 243 memset(&fl, 0, sizeof fl);
272 fl.nl_u.ip6_u.daddr = dst_in->sin6_addr; 244 ipv6_addr_copy(&fl.fl6_dst, &dst_in->sin6_addr);
273 fl.nl_u.ip6_u.saddr = src_in->sin6_addr; 245 ipv6_addr_copy(&fl.fl6_src, &src_in->sin6_addr);
274 fl.oif = addr->bound_dev_if; 246 fl.oif = addr->bound_dev_if;
275 247
276 dst = ip6_route_output(&init_net, NULL, &fl); 248 dst = ip6_route_output(&init_net, NULL, &fl);
277 if (!dst) 249 if ((ret = dst->error))
278 return ret; 250 goto put;
251
252 if (ipv6_addr_any(&fl.fl6_src)) {
253 ret = ipv6_dev_get_saddr(&init_net, ip6_dst_idev(dst)->dev,
254 &fl.fl6_dst, 0, &fl.fl6_src);
255 if (ret)
256 goto put;
279 257
258 src_in->sin6_family = AF_INET6;
259 ipv6_addr_copy(&src_in->sin6_addr, &fl.fl6_src);
260 }
261
262 if (dst->dev->flags & IFF_LOOPBACK) {
263 ret = rdma_translate_ip((struct sockaddr *) dst_in, addr);
264 if (!ret)
265 memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN);
266 goto put;
267 }
268
269 /* If the device does ARP internally, return 'done' */
280 if (dst->dev->flags & IFF_NOARP) { 270 if (dst->dev->flags & IFF_NOARP) {
281 ret = rdma_copy_addr(addr, dst->dev, NULL); 271 ret = rdma_copy_addr(addr, dst->dev, NULL);
282 } else { 272 goto put;
283 neigh = dst->neighbour;
284 if (neigh && (neigh->nud_state & NUD_VALID))
285 ret = rdma_copy_addr(addr, neigh->dev, neigh->ha);
286 } 273 }
287 274
275 neigh = dst->neighbour;
276 if (!neigh || !(neigh->nud_state & NUD_VALID)) {
277 neigh_event_send(dst->neighbour, NULL);
278 ret = -ENODATA;
279 goto put;
280 }
281
282 ret = rdma_copy_addr(addr, dst->dev, neigh->ha);
283put:
288 dst_release(dst); 284 dst_release(dst);
289 return ret; 285 return ret;
290} 286}
291#else 287#else
292static int addr6_resolve_remote(struct sockaddr_in6 *src_in, 288static int addr6_resolve(struct sockaddr_in6 *src_in,
293 struct sockaddr_in6 *dst_in, 289 struct sockaddr_in6 *dst_in,
294 struct rdma_dev_addr *addr) 290 struct rdma_dev_addr *addr)
295{ 291{
296 return -EADDRNOTAVAIL; 292 return -EADDRNOTAVAIL;
297} 293}
@@ -305,7 +301,7 @@ static int addr_resolve(struct sockaddr *src_in,
305 return addr4_resolve((struct sockaddr_in *) src_in, 301 return addr4_resolve((struct sockaddr_in *) src_in,
306 (struct sockaddr_in *) dst_in, addr); 302 (struct sockaddr_in *) dst_in, addr);
307 } else 303 } else
308 return addr6_resolve_remote((struct sockaddr_in6 *) src_in, 304 return addr6_resolve((struct sockaddr_in6 *) src_in,
309 (struct sockaddr_in6 *) dst_in, addr); 305 (struct sockaddr_in6 *) dst_in, addr);
310} 306}
311 307
@@ -346,60 +342,6 @@ static void process_req(struct work_struct *work)
346 } 342 }
347} 343}
348 344
349static int addr_resolve_local(struct sockaddr *src_in,
350 struct sockaddr *dst_in,
351 struct rdma_dev_addr *addr)
352{
353 struct net_device *dev;
354 int ret;
355
356 switch (dst_in->sa_family) {
357#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
358 case AF_INET6:
359 {
360 struct in6_addr *a;
361
362 read_lock(&dev_base_lock);
363 for_each_netdev(&init_net, dev)
364 if (ipv6_chk_addr(&init_net,
365 &((struct sockaddr_in6 *) dst_in)->sin6_addr,
366 dev, 1))
367 break;
368
369 if (!dev) {
370 read_unlock(&dev_base_lock);
371 return -EADDRNOTAVAIL;
372 }
373
374 a = &((struct sockaddr_in6 *) src_in)->sin6_addr;
375
376 if (ipv6_addr_any(a)) {
377 src_in->sa_family = dst_in->sa_family;
378 ((struct sockaddr_in6 *) src_in)->sin6_addr =
379 ((struct sockaddr_in6 *) dst_in)->sin6_addr;
380 ret = rdma_copy_addr(addr, dev, dev->dev_addr);
381 } else if (ipv6_addr_loopback(a)) {
382 ret = rdma_translate_ip(dst_in, addr);
383 if (!ret)
384 memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
385 } else {
386 ret = rdma_translate_ip(src_in, addr);
387 if (!ret)
388 memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
389 }
390 read_unlock(&dev_base_lock);
391 break;
392 }
393#endif
394
395 default:
396 ret = -EADDRNOTAVAIL;
397 break;
398 }
399
400 return ret;
401}
402
403int rdma_resolve_ip(struct rdma_addr_client *client, 345int rdma_resolve_ip(struct rdma_addr_client *client,
404 struct sockaddr *src_addr, struct sockaddr *dst_addr, 346 struct sockaddr *src_addr, struct sockaddr *dst_addr,
405 struct rdma_dev_addr *addr, int timeout_ms, 347 struct rdma_dev_addr *addr, int timeout_ms,
@@ -436,10 +378,7 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
436 req->client = client; 378 req->client = client;
437 atomic_inc(&client->refcount); 379 atomic_inc(&client->refcount);
438 380
439 req->status = addr_resolve_local(src_in, dst_in, addr); 381 req->status = addr_resolve(src_in, dst_in, addr);
440 if (req->status == -EADDRNOTAVAIL)
441 req->status = addr_resolve(src_in, dst_in, addr);
442
443 switch (req->status) { 382 switch (req->status) {
444 case 0: 383 case 0:
445 req->timeout = jiffies; 384 req->timeout = jiffies;
@@ -448,7 +387,6 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
448 case -ENODATA: 387 case -ENODATA:
449 req->timeout = msecs_to_jiffies(timeout_ms) + jiffies; 388 req->timeout = msecs_to_jiffies(timeout_ms) + jiffies;
450 queue_req(req); 389 queue_req(req);
451 addr_send_arp(dst_in);
452 break; 390 break;
453 default: 391 default:
454 ret = req->status; 392 ret = req->status;
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 38867a46d39e..fbdd73106000 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -1472,15 +1472,6 @@ static void cma_listen_on_all(struct rdma_id_private *id_priv)
1472 mutex_unlock(&lock); 1472 mutex_unlock(&lock);
1473} 1473}
1474 1474
1475static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af)
1476{
1477 struct sockaddr_storage addr_in;
1478
1479 memset(&addr_in, 0, sizeof addr_in);
1480 addr_in.ss_family = af;
1481 return rdma_bind_addr(id, (struct sockaddr *) &addr_in);
1482}
1483
1484int rdma_listen(struct rdma_cm_id *id, int backlog) 1475int rdma_listen(struct rdma_cm_id *id, int backlog)
1485{ 1476{
1486 struct rdma_id_private *id_priv; 1477 struct rdma_id_private *id_priv;
@@ -1488,7 +1479,8 @@ int rdma_listen(struct rdma_cm_id *id, int backlog)
1488 1479
1489 id_priv = container_of(id, struct rdma_id_private, id); 1480 id_priv = container_of(id, struct rdma_id_private, id);
1490 if (id_priv->state == CMA_IDLE) { 1481 if (id_priv->state == CMA_IDLE) {
1491 ret = cma_bind_any(id, AF_INET); 1482 ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
1483 ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
1492 if (ret) 1484 if (ret)
1493 return ret; 1485 return ret;
1494 } 1486 }
@@ -1885,10 +1877,14 @@ err:
1885static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 1877static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
1886 struct sockaddr *dst_addr) 1878 struct sockaddr *dst_addr)
1887{ 1879{
1888 if (src_addr && src_addr->sa_family) 1880 if (!src_addr || !src_addr->sa_family) {
1889 return rdma_bind_addr(id, src_addr); 1881 src_addr = (struct sockaddr *) &id->route.addr.src_addr;
1890 else 1882 if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) {
1891 return cma_bind_any(id, dst_addr->sa_family); 1883 ((struct sockaddr_in6 *) src_addr)->sin6_scope_id =
1884 ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id;
1885 }
1886 }
1887 return rdma_bind_addr(id, src_addr);
1892} 1888}
1893 1889
1894int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 1890int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
@@ -2084,6 +2080,25 @@ static int cma_get_port(struct rdma_id_private *id_priv)
2084 return ret; 2080 return ret;
2085} 2081}
2086 2082
2083static int cma_check_linklocal(struct rdma_dev_addr *dev_addr,
2084 struct sockaddr *addr)
2085{
2086#if defined(CONFIG_IPv6) || defined(CONFIG_IPV6_MODULE)
2087 struct sockaddr_in6 *sin6;
2088
2089 if (addr->sa_family != AF_INET6)
2090 return 0;
2091
2092 sin6 = (struct sockaddr_in6 *) addr;
2093 if ((ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
2094 !sin6->sin6_scope_id)
2095 return -EINVAL;
2096
2097 dev_addr->bound_dev_if = sin6->sin6_scope_id;
2098#endif
2099 return 0;
2100}
2101
2087int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 2102int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
2088{ 2103{
2089 struct rdma_id_private *id_priv; 2104 struct rdma_id_private *id_priv;
@@ -2096,6 +2111,10 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
2096 if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND)) 2111 if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND))
2097 return -EINVAL; 2112 return -EINVAL;
2098 2113
2114 ret = cma_check_linklocal(&id->route.addr.dev_addr, addr);
2115 if (ret)
2116 goto err1;
2117
2099 if (cma_loopback_addr(addr)) { 2118 if (cma_loopback_addr(addr)) {
2100 ret = cma_bind_loopback(id_priv); 2119 ret = cma_bind_loopback(id_priv);
2101 } else if (!cma_zero_addr(addr)) { 2120 } else if (!cma_zero_addr(addr)) {