diff options
| -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) | 
