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 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD$"); 34 35#include <sys/param.h> 36#include <sys/condvar.h> 37#include <sys/systm.h> 38#include <sys/kernel.h> 39#include <sys/socket.h> 40#include <sys/module.h> 41 42#include <sys/lock.h> 43#include <sys/condvar.h> 44#include <sys/mutex.h> 45#include <sys/rwlock.h> 46#include <sys/queue.h> 47#include <sys/taskqueue.h> 48 49#include <net/if.h> 50#include <net/if_dl.h> 51#include <net/if_var.h> 52#include <net/if_arp.h> 53#include <net/route.h> 54 55#include <net80211/ieee80211_freebsd.h> 56 57#include <netinet/in.h> 58#include <netinet/if_ether.h> 59 60#include <contrib/rdma/ib_addr.h> 61 62struct addr_req { 63 TAILQ_ENTRY(addr_req) entry; 64 struct sockaddr src_addr; 65 struct sockaddr dst_addr; 66 struct rdma_dev_addr *addr; 67 struct rdma_addr_client *client; 68 void *context; 69 void (*callback)(int status, struct sockaddr *src_addr, 70 struct rdma_dev_addr *addr, void *context); 71 unsigned long timeout; 72 int status; 73}; 74 75static void process_req(void *ctx, int pending); 76 77static struct mtx lock; 78 79static TAILQ_HEAD(addr_req_list, addr_req) req_list; 80static struct task addr_task; 81static struct taskqueue *addr_taskq; 82static struct callout addr_ch; 83static eventhandler_tag route_event_tag; 84 85static void addr_timeout(void *arg) 86{ 87 taskqueue_enqueue(addr_taskq, &addr_task); 88} 89 90void rdma_addr_register_client(struct rdma_addr_client *client) 91{ 92 mtx_init(&client->lock, "rdma_addr client lock", NULL, MTX_DUPOK|MTX_DEF); 93 cv_init(&client->comp, "rdma_addr cv"); 94 client->refcount = 1; 95} 96 97static inline void put_client(struct rdma_addr_client *client) 98{ 99 mtx_lock(&client->lock); 100 if (--client->refcount == 0) { 101 cv_broadcast(&client->comp); 102 } 103 mtx_unlock(&client->lock); 104} 105 106void rdma_addr_unregister_client(struct rdma_addr_client *client) 107{ 108 put_client(client); 109 mtx_lock(&client->lock); 110 if (client->refcount) { 111 cv_wait(&client->comp, &client->lock); 112 } 113 mtx_unlock(&client->lock); 114} 115 116int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct ifnet *dev, 117 const unsigned char *dst_dev_addr) 118{ 119 dev_addr->dev_type = RDMA_NODE_RNIC; 120 memset(dev_addr->src_dev_addr, 0, MAX_ADDR_LEN); 121 memcpy(dev_addr->src_dev_addr, IF_LLADDR(dev), dev->if_addrlen); 122 memcpy(dev_addr->broadcast, dev->if_broadcastaddr, MAX_ADDR_LEN); 123 if (dst_dev_addr) 124 memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN); 125 return 0; 126} 127 128int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) 129{ 130 struct ifaddr *ifa; 131 struct sockaddr_in *sin = (struct sockaddr_in *)addr; 132 uint16_t port = sin->sin_port; 133 int ret; 134 135 sin->sin_port = 0; 136 ifa = ifa_ifwithaddr(addr); 137 sin->sin_port = port; 138 if (!ifa) 139 return (EADDRNOTAVAIL); 140 ret = rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL); 141 ifa_free(ifa); 142 return (ret); 143} 144 145static void queue_req(struct addr_req *req) 146{ 147 struct addr_req *tmp_req = NULL; 148 149 mtx_lock(&lock); 150 TAILQ_FOREACH_REVERSE(tmp_req, &req_list, addr_req_list, entry) 151 if (time_after_eq(req->timeout, tmp_req->timeout)) 152 break; 153 154 if (tmp_req) 155 TAILQ_INSERT_AFTER(&req_list, tmp_req, req, entry); 156 else 157 TAILQ_INSERT_TAIL(&req_list, req, entry); 158 159 if (TAILQ_FIRST(&req_list) == req) 160 callout_reset(&addr_ch, req->timeout - ticks, addr_timeout, NULL); 161 mtx_unlock(&lock); 162} 163 164#ifdef needed 165static void addr_send_arp(struct sockaddr_in *dst_in) 166{ 167 struct route iproute; 168 struct sockaddr_in *dst = (struct sockaddr_in *)&iproute.ro_dst; 169 char dmac[ETHER_ADDR_LEN]; 170 struct llentry *lle; 171 172 bzero(&iproute, sizeof iproute); 173 *dst = *dst_in; 174 175 rtalloc(&iproute); 176 if (iproute.ro_rt == NULL); 177 return; 178 179 arpresolve(iproute.ro_rt->rt_ifp, iproute.ro_rt, NULL, 180 rt_key(iproute.ro_rt), dmac, &lle); 181 182 RTFREE(iproute.ro_rt); 183} 184#endif 185 186static int addr_resolve_remote(struct sockaddr_in *src_in, 187 struct sockaddr_in *dst_in, 188 struct rdma_dev_addr *addr) 189{ 190 int ret = 0; 191 struct route iproute; 192 struct sockaddr_in *dst = (struct sockaddr_in *)&iproute.ro_dst; 193 char dmac[ETHER_ADDR_LEN]; 194 struct llentry *lle; 195 196 bzero(&iproute, sizeof iproute); 197 *dst = *dst_in; 198 199 rtalloc(&iproute); 200 if (iproute.ro_rt == NULL) { 201 ret = EHOSTUNREACH; 202 goto out; 203 } 204 205 /* If the device does ARP internally, return 'done' */ 206 if (iproute.ro_rt->rt_ifp->if_flags & IFF_NOARP) { 207 rdma_copy_addr(addr, iproute.ro_rt->rt_ifp, NULL); 208 goto put; 209 } 210 ret = arpresolve(iproute.ro_rt->rt_ifp, iproute.ro_rt, NULL, 211 (struct sockaddr *)dst_in, dmac, &lle); 212 if (ret) { 213 goto put; 214 } 215 216 if (!src_in->sin_addr.s_addr) { 217 src_in->sin_len = sizeof *src_in; 218 src_in->sin_family = dst_in->sin_family; 219 src_in->sin_addr.s_addr = ((struct sockaddr_in *)iproute.ro_rt->rt_ifa->ifa_addr)->sin_addr.s_addr; 220 } 221 222 ret = rdma_copy_addr(addr, iproute.ro_rt->rt_ifp, dmac); 223put: 224 RTFREE(iproute.ro_rt); 225out: 226 return ret; 227} 228 229static void process_req(void *ctx, int pending) 230{ 231 struct addr_req *req, *tmp_req; 232 struct sockaddr_in *src_in, *dst_in; 233 TAILQ_HEAD(, addr_req) done_list; 234 235 TAILQ_INIT(&done_list); 236 237 mtx_lock(&lock); 238 TAILQ_FOREACH_SAFE(req, &req_list, entry, tmp_req) { 239 if (req->status == EWOULDBLOCK) { 240 src_in = (struct sockaddr_in *) &req->src_addr; 241 dst_in = (struct sockaddr_in *) &req->dst_addr; 242 req->status = addr_resolve_remote(src_in, dst_in, 243 req->addr); 244 if (req->status && time_after_eq(ticks, req->timeout)) 245 req->status = ETIMEDOUT; 246 else if (req->status == EWOULDBLOCK) 247 continue; 248 } 249 TAILQ_REMOVE(&req_list, req, entry); 250 TAILQ_INSERT_TAIL(&done_list, req, entry); 251 } 252 253 if (!TAILQ_EMPTY(&req_list)) { 254 req = TAILQ_FIRST(&req_list); 255 callout_reset(&addr_ch, req->timeout - ticks, addr_timeout, 256 NULL); 257 } 258 mtx_unlock(&lock); 259 260 TAILQ_FOREACH_SAFE(req, &done_list, entry, tmp_req) { 261 TAILQ_REMOVE(&done_list, req, entry); 262 req->callback(req->status, &req->src_addr, req->addr, 263 req->context); 264 put_client(req->client); 265 free(req, M_DEVBUF); 266 } 267} 268 269int rdma_resolve_ip(struct rdma_addr_client *client, 270 struct sockaddr *src_addr, struct sockaddr *dst_addr, 271 struct rdma_dev_addr *addr, int timeout_ms, 272 void (*callback)(int status, struct sockaddr *src_addr, 273 struct rdma_dev_addr *addr, void *context), 274 void *context) 275{ 276 struct sockaddr_in *src_in, *dst_in; 277 struct addr_req *req; 278 int ret = 0; 279 280 req = malloc(sizeof *req, M_DEVBUF, M_NOWAIT); 281 if (!req) 282 return (ENOMEM); 283 memset(req, 0, sizeof *req); 284 285 if (src_addr) 286 memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr)); 287 memcpy(&req->dst_addr, dst_addr, ip_addr_size(dst_addr)); 288 req->addr = addr; 289 req->callback = callback; 290 req->context = context; 291 req->client = client; 292 mtx_lock(&client->lock); 293 client->refcount++; 294 mtx_unlock(&client->lock); 295 296 src_in = (struct sockaddr_in *) &req->src_addr; 297 dst_in = (struct sockaddr_in *) &req->dst_addr; 298 299 req->status = addr_resolve_remote(src_in, dst_in, addr); 300 301 switch (req->status) { 302 case 0: 303 req->timeout = ticks; 304 queue_req(req); 305 break; 306 case EWOULDBLOCK: 307 req->timeout = msecs_to_ticks(timeout_ms) + ticks; 308 queue_req(req); 309#ifdef needed 310 addr_send_arp(dst_in); 311#endif 312 break; 313 default: 314 ret = req->status; 315 mtx_lock(&client->lock); 316 client->refcount--; 317 mtx_unlock(&client->lock); 318 free(req, M_DEVBUF); 319 break; 320 } 321 return ret; 322} 323 324void rdma_addr_cancel(struct rdma_dev_addr *addr) 325{ 326 struct addr_req *req, *tmp_req; 327 328 mtx_lock(&lock); 329 TAILQ_FOREACH_SAFE(req, &req_list, entry, tmp_req) { 330 if (req->addr == addr) { 331 req->status = ECANCELED; 332 req->timeout = ticks; 333 TAILQ_REMOVE(&req_list, req, entry); 334 TAILQ_INSERT_HEAD(&req_list, req, entry); 335 callout_reset(&addr_ch, req->timeout - ticks, addr_timeout, NULL); 336 break; 337 } 338 } 339 mtx_unlock(&lock); 340} 341 342static void 343route_event_arp_update(void *unused, struct rtentry *rt0, uint8_t *enaddr, 344 struct sockaddr *sa) 345{ 346 callout_stop(&addr_ch); 347 taskqueue_enqueue(addr_taskq, &addr_task); 348} 349 350static int addr_init(void) 351{ 352 TAILQ_INIT(&req_list); 353 mtx_init(&lock, "rdma_addr req_list lock", NULL, MTX_DEF); 354 355 addr_taskq = taskqueue_create("rdma_addr_taskq", M_NOWAIT, 356 taskqueue_thread_enqueue, &addr_taskq); 357 if (addr_taskq == NULL) { 358 printf("failed to allocate rdma_addr taskqueue\n"); 359 return (ENOMEM); 360 } 361 taskqueue_start_threads(&addr_taskq, 1, PI_NET, "rdma_addr taskq"); 362 TASK_INIT(&addr_task, 0, process_req, NULL); 363 364 callout_init(&addr_ch, TRUE); 365 366 route_event_tag = EVENTHANDLER_REGISTER(route_arp_update_event, 367 route_event_arp_update, NULL, EVENTHANDLER_PRI_ANY); 368 369 return 0; 370} 371 372static void addr_cleanup(void) 373{ 374 EVENTHANDLER_DEREGISTER(route_event_arp_update, route_event_tag); 375 callout_stop(&addr_ch); 376 taskqueue_drain(addr_taskq, &addr_task); 377 taskqueue_free(addr_taskq); 378} 379 380static int 381addr_load(module_t mod, int cmd, void *arg) 382{ 383 int err = 0; 384 385 switch (cmd) { 386 case MOD_LOAD: 387 printf("Loading rdma_addr.\n"); 388 389 addr_init(); 390 break; 391 case MOD_QUIESCE: 392 break; 393 case MOD_UNLOAD: 394 printf("Unloading rdma_addr.\n"); 395 addr_cleanup(); 396 break; 397 case MOD_SHUTDOWN: 398 break; 399 default: 400 err = EOPNOTSUPP; 401 break; 402 } 403 404 return (err); 405} 406 407static moduledata_t mod_data = { 408 "rdma_addr", 409 addr_load, 410 0 411}; 412 413MODULE_VERSION(rdma_addr, 1); 414DECLARE_MODULE(rdma_addr, mod_data, SI_SUB_EXEC, SI_ORDER_ANY); 415