addr.c revision 07ebafbaaa72aa6a35472879008f5a1d1d469a0c
1/* 2 * Copyright (c) 2005 Voltaire Inc. All rights reserved. 3 * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. 4 * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. 5 * Copyright (c) 2005 Intel Corporation. All rights reserved. 6 * 7 * This Software is licensed under one of the following licenses: 8 * 9 * 1) under the terms of the "Common Public License 1.0" a copy of which is 10 * available from the Open Source Initiative, see 11 * http://www.opensource.org/licenses/cpl.php. 12 * 13 * 2) under the terms of the "The BSD License" a copy of which is 14 * available from the Open Source Initiative, see 15 * http://www.opensource.org/licenses/bsd-license.php. 16 * 17 * 3) under the terms of the "GNU General Public License (GPL) Version 2" a 18 * copy of which is available from the Open Source Initiative, see 19 * http://www.opensource.org/licenses/gpl-license.php. 20 * 21 * Licensee has the right to choose one of the above licenses. 22 * 23 * Redistributions of source code must retain the above copyright 24 * notice and one of the license notices. 25 * 26 * Redistributions in binary form must reproduce both the above copyright 27 * notice, one of the license notices in the documentation 28 * and/or other materials provided with the distribution. 29 */ 30 31#include <linux/mutex.h> 32#include <linux/inetdevice.h> 33#include <linux/workqueue.h> 34#include <linux/if_arp.h> 35#include <net/arp.h> 36#include <net/neighbour.h> 37#include <net/route.h> 38#include <net/netevent.h> 39#include <rdma/ib_addr.h> 40 41MODULE_AUTHOR("Sean Hefty"); 42MODULE_DESCRIPTION("IB Address Translation"); 43MODULE_LICENSE("Dual BSD/GPL"); 44 45struct addr_req { 46 struct list_head list; 47 struct sockaddr src_addr; 48 struct sockaddr dst_addr; 49 struct rdma_dev_addr *addr; 50 void *context; 51 void (*callback)(int status, struct sockaddr *src_addr, 52 struct rdma_dev_addr *addr, void *context); 53 unsigned long timeout; 54 int status; 55}; 56 57static void process_req(void *data); 58 59static DEFINE_MUTEX(lock); 60static LIST_HEAD(req_list); 61static DECLARE_WORK(work, process_req, NULL); 62static struct workqueue_struct *addr_wq; 63 64int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, 65 const unsigned char *dst_dev_addr) 66{ 67 switch (dev->type) { 68 case ARPHRD_INFINIBAND: 69 dev_addr->dev_type = RDMA_NODE_IB_CA; 70 break; 71 case ARPHRD_ETHER: 72 dev_addr->dev_type = RDMA_NODE_RNIC; 73 break; 74 default: 75 return -EADDRNOTAVAIL; 76 } 77 78 memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN); 79 memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN); 80 if (dst_dev_addr) 81 memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN); 82 return 0; 83} 84EXPORT_SYMBOL(rdma_copy_addr); 85 86int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) 87{ 88 struct net_device *dev; 89 u32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr; 90 int ret; 91 92 dev = ip_dev_find(ip); 93 if (!dev) 94 return -EADDRNOTAVAIL; 95 96 ret = rdma_copy_addr(dev_addr, dev, NULL); 97 dev_put(dev); 98 return ret; 99} 100EXPORT_SYMBOL(rdma_translate_ip); 101 102static void set_timeout(unsigned long time) 103{ 104 unsigned long delay; 105 106 cancel_delayed_work(&work); 107 108 delay = time - jiffies; 109 if ((long)delay <= 0) 110 delay = 1; 111 112 queue_delayed_work(addr_wq, &work, delay); 113} 114 115static void queue_req(struct addr_req *req) 116{ 117 struct addr_req *temp_req; 118 119 mutex_lock(&lock); 120 list_for_each_entry_reverse(temp_req, &req_list, list) { 121 if (time_after(req->timeout, temp_req->timeout)) 122 break; 123 } 124 125 list_add(&req->list, &temp_req->list); 126 127 if (req_list.next == &req->list) 128 set_timeout(req->timeout); 129 mutex_unlock(&lock); 130} 131 132static void addr_send_arp(struct sockaddr_in *dst_in) 133{ 134 struct rtable *rt; 135 struct flowi fl; 136 u32 dst_ip = dst_in->sin_addr.s_addr; 137 138 memset(&fl, 0, sizeof fl); 139 fl.nl_u.ip4_u.daddr = dst_ip; 140 if (ip_route_output_key(&rt, &fl)) 141 return; 142 143 arp_send(ARPOP_REQUEST, ETH_P_ARP, rt->rt_gateway, rt->idev->dev, 144 rt->rt_src, NULL, rt->idev->dev->dev_addr, NULL); 145 ip_rt_put(rt); 146} 147 148static int addr_resolve_remote(struct sockaddr_in *src_in, 149 struct sockaddr_in *dst_in, 150 struct rdma_dev_addr *addr) 151{ 152 u32 src_ip = src_in->sin_addr.s_addr; 153 u32 dst_ip = dst_in->sin_addr.s_addr; 154 struct flowi fl; 155 struct rtable *rt; 156 struct neighbour *neigh; 157 int ret; 158 159 memset(&fl, 0, sizeof fl); 160 fl.nl_u.ip4_u.daddr = dst_ip; 161 fl.nl_u.ip4_u.saddr = src_ip; 162 ret = ip_route_output_key(&rt, &fl); 163 if (ret) 164 goto out; 165 166 /* If the device does ARP internally, return 'done' */ 167 if (rt->idev->dev->flags & IFF_NOARP) { 168 rdma_copy_addr(addr, rt->idev->dev, NULL); 169 goto put; 170 } 171 172 neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev); 173 if (!neigh) { 174 ret = -ENODATA; 175 goto put; 176 } 177 178 if (!(neigh->nud_state & NUD_VALID)) { 179 ret = -ENODATA; 180 goto release; 181 } 182 183 if (!src_ip) { 184 src_in->sin_family = dst_in->sin_family; 185 src_in->sin_addr.s_addr = rt->rt_src; 186 } 187 188 ret = rdma_copy_addr(addr, neigh->dev, neigh->ha); 189release: 190 neigh_release(neigh); 191put: 192 ip_rt_put(rt); 193out: 194 return ret; 195} 196 197static void process_req(void *data) 198{ 199 struct addr_req *req, *temp_req; 200 struct sockaddr_in *src_in, *dst_in; 201 struct list_head done_list; 202 203 INIT_LIST_HEAD(&done_list); 204 205 mutex_lock(&lock); 206 list_for_each_entry_safe(req, temp_req, &req_list, list) { 207 if (req->status) { 208 src_in = (struct sockaddr_in *) &req->src_addr; 209 dst_in = (struct sockaddr_in *) &req->dst_addr; 210 req->status = addr_resolve_remote(src_in, dst_in, 211 req->addr); 212 } 213 if (req->status && time_after(jiffies, req->timeout)) 214 req->status = -ETIMEDOUT; 215 else if (req->status == -ENODATA) 216 continue; 217 218 list_del(&req->list); 219 list_add_tail(&req->list, &done_list); 220 } 221 222 if (!list_empty(&req_list)) { 223 req = list_entry(req_list.next, struct addr_req, list); 224 set_timeout(req->timeout); 225 } 226 mutex_unlock(&lock); 227 228 list_for_each_entry_safe(req, temp_req, &done_list, list) { 229 list_del(&req->list); 230 req->callback(req->status, &req->src_addr, req->addr, 231 req->context); 232 kfree(req); 233 } 234} 235 236static int addr_resolve_local(struct sockaddr_in *src_in, 237 struct sockaddr_in *dst_in, 238 struct rdma_dev_addr *addr) 239{ 240 struct net_device *dev; 241 u32 src_ip = src_in->sin_addr.s_addr; 242 u32 dst_ip = dst_in->sin_addr.s_addr; 243 int ret; 244 245 dev = ip_dev_find(dst_ip); 246 if (!dev) 247 return -EADDRNOTAVAIL; 248 249 if (ZERONET(src_ip)) { 250 src_in->sin_family = dst_in->sin_family; 251 src_in->sin_addr.s_addr = dst_ip; 252 ret = rdma_copy_addr(addr, dev, dev->dev_addr); 253 } else if (LOOPBACK(src_ip)) { 254 ret = rdma_translate_ip((struct sockaddr *)dst_in, addr); 255 if (!ret) 256 memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); 257 } else { 258 ret = rdma_translate_ip((struct sockaddr *)src_in, addr); 259 if (!ret) 260 memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); 261 } 262 263 dev_put(dev); 264 return ret; 265} 266 267int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, 268 struct rdma_dev_addr *addr, int timeout_ms, 269 void (*callback)(int status, struct sockaddr *src_addr, 270 struct rdma_dev_addr *addr, void *context), 271 void *context) 272{ 273 struct sockaddr_in *src_in, *dst_in; 274 struct addr_req *req; 275 int ret = 0; 276 277 req = kmalloc(sizeof *req, GFP_KERNEL); 278 if (!req) 279 return -ENOMEM; 280 memset(req, 0, sizeof *req); 281 282 if (src_addr) 283 memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr)); 284 memcpy(&req->dst_addr, dst_addr, ip_addr_size(dst_addr)); 285 req->addr = addr; 286 req->callback = callback; 287 req->context = context; 288 289 src_in = (struct sockaddr_in *) &req->src_addr; 290 dst_in = (struct sockaddr_in *) &req->dst_addr; 291 292 req->status = addr_resolve_local(src_in, dst_in, addr); 293 if (req->status == -EADDRNOTAVAIL) 294 req->status = addr_resolve_remote(src_in, dst_in, addr); 295 296 switch (req->status) { 297 case 0: 298 req->timeout = jiffies; 299 queue_req(req); 300 break; 301 case -ENODATA: 302 req->timeout = msecs_to_jiffies(timeout_ms) + jiffies; 303 queue_req(req); 304 addr_send_arp(dst_in); 305 break; 306 default: 307 ret = req->status; 308 kfree(req); 309 break; 310 } 311 return ret; 312} 313EXPORT_SYMBOL(rdma_resolve_ip); 314 315void rdma_addr_cancel(struct rdma_dev_addr *addr) 316{ 317 struct addr_req *req, *temp_req; 318 319 mutex_lock(&lock); 320 list_for_each_entry_safe(req, temp_req, &req_list, list) { 321 if (req->addr == addr) { 322 req->status = -ECANCELED; 323 req->timeout = jiffies; 324 list_del(&req->list); 325 list_add(&req->list, &req_list); 326 set_timeout(req->timeout); 327 break; 328 } 329 } 330 mutex_unlock(&lock); 331} 332EXPORT_SYMBOL(rdma_addr_cancel); 333 334static int netevent_callback(struct notifier_block *self, unsigned long event, 335 void *ctx) 336{ 337 if (event == NETEVENT_NEIGH_UPDATE) { 338 struct neighbour *neigh = ctx; 339 340 if (neigh->dev->type == ARPHRD_INFINIBAND && 341 (neigh->nud_state & NUD_VALID)) { 342 set_timeout(jiffies); 343 } 344 } 345 return 0; 346} 347 348static struct notifier_block nb = { 349 .notifier_call = netevent_callback 350}; 351 352static int addr_init(void) 353{ 354 addr_wq = create_singlethread_workqueue("ib_addr_wq"); 355 if (!addr_wq) 356 return -ENOMEM; 357 358 register_netevent_notifier(&nb); 359 return 0; 360} 361 362static void addr_cleanup(void) 363{ 364 unregister_netevent_notifier(&nb); 365 destroy_workqueue(addr_wq); 366} 367 368module_init(addr_init); 369module_exit(addr_cleanup); 370