1178784Skmacy/* 2178784Skmacy * Copyright (c) 2005 Voltaire Inc. All rights reserved. 3178784Skmacy * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. 4178784Skmacy * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. 5178784Skmacy * Copyright (c) 2005 Intel Corporation. All rights reserved. 6178784Skmacy * 7178784Skmacy * This Software is licensed under one of the following licenses: 8178784Skmacy * 9178784Skmacy * 1) under the terms of the "Common Public License 1.0" a copy of which is 10178784Skmacy * available from the Open Source Initiative, see 11178784Skmacy * http://www.opensource.org/licenses/cpl.php. 12178784Skmacy * 13178784Skmacy * 2) under the terms of the "The BSD License" a copy of which is 14178784Skmacy * available from the Open Source Initiative, see 15178784Skmacy * http://www.opensource.org/licenses/bsd-license.php. 16178784Skmacy * 17178784Skmacy * 3) under the terms of the "GNU General Public License (GPL) Version 2" a 18178784Skmacy * copy of which is available from the Open Source Initiative, see 19178784Skmacy * http://www.opensource.org/licenses/gpl-license.php. 20178784Skmacy * 21178784Skmacy * Licensee has the right to choose one of the above licenses. 22178784Skmacy * 23178784Skmacy * Redistributions of source code must retain the above copyright 24178784Skmacy * notice and one of the license notices. 25178784Skmacy * 26178784Skmacy * Redistributions in binary form must reproduce both the above copyright 27178784Skmacy * notice, one of the license notices in the documentation 28178784Skmacy * and/or other materials provided with the distribution. 29178784Skmacy * 30178784Skmacy */ 31178784Skmacy 32178784Skmacy#include <sys/cdefs.h> 33178784Skmacy__FBSDID("$FreeBSD$"); 34178784Skmacy 35178784Skmacy#include <sys/param.h> 36178784Skmacy#include <sys/condvar.h> 37178784Skmacy#include <sys/systm.h> 38178784Skmacy#include <sys/kernel.h> 39178784Skmacy#include <sys/socket.h> 40178784Skmacy#include <sys/module.h> 41178784Skmacy 42178784Skmacy#include <sys/lock.h> 43178784Skmacy#include <sys/condvar.h> 44178784Skmacy#include <sys/mutex.h> 45178784Skmacy#include <sys/rwlock.h> 46178784Skmacy#include <sys/queue.h> 47178784Skmacy#include <sys/taskqueue.h> 48178784Skmacy 49178784Skmacy#include <net/if.h> 50178784Skmacy#include <net/if_dl.h> 51178784Skmacy#include <net/if_var.h> 52178784Skmacy#include <net/if_arp.h> 53178784Skmacy#include <net/route.h> 54178784Skmacy 55178784Skmacy#include <net80211/ieee80211_freebsd.h> 56178784Skmacy 57178784Skmacy#include <netinet/in.h> 58178784Skmacy#include <netinet/if_ether.h> 59178784Skmacy 60178784Skmacy#include <contrib/rdma/ib_addr.h> 61178784Skmacy 62178784Skmacystruct addr_req { 63178784Skmacy TAILQ_ENTRY(addr_req) entry; 64178784Skmacy struct sockaddr src_addr; 65178784Skmacy struct sockaddr dst_addr; 66178784Skmacy struct rdma_dev_addr *addr; 67178784Skmacy struct rdma_addr_client *client; 68178784Skmacy void *context; 69178784Skmacy void (*callback)(int status, struct sockaddr *src_addr, 70178784Skmacy struct rdma_dev_addr *addr, void *context); 71178784Skmacy unsigned long timeout; 72178784Skmacy int status; 73178784Skmacy}; 74178784Skmacy 75178784Skmacystatic void process_req(void *ctx, int pending); 76178784Skmacy 77178784Skmacystatic struct mtx lock; 78178784Skmacy 79178784Skmacystatic TAILQ_HEAD(addr_req_list, addr_req) req_list; 80178784Skmacystatic struct task addr_task; 81178784Skmacystatic struct taskqueue *addr_taskq; 82178784Skmacystatic struct callout addr_ch; 83178784Skmacystatic eventhandler_tag route_event_tag; 84178784Skmacy 85178784Skmacystatic void addr_timeout(void *arg) 86178784Skmacy{ 87178784Skmacy taskqueue_enqueue(addr_taskq, &addr_task); 88178784Skmacy} 89178784Skmacy 90178784Skmacyvoid rdma_addr_register_client(struct rdma_addr_client *client) 91178784Skmacy{ 92178784Skmacy mtx_init(&client->lock, "rdma_addr client lock", NULL, MTX_DUPOK|MTX_DEF); 93178784Skmacy cv_init(&client->comp, "rdma_addr cv"); 94178784Skmacy client->refcount = 1; 95178784Skmacy} 96178784Skmacy 97178784Skmacystatic inline void put_client(struct rdma_addr_client *client) 98178784Skmacy{ 99178784Skmacy mtx_lock(&client->lock); 100178784Skmacy if (--client->refcount == 0) { 101178784Skmacy cv_broadcast(&client->comp); 102178784Skmacy } 103178784Skmacy mtx_unlock(&client->lock); 104178784Skmacy} 105178784Skmacy 106178784Skmacyvoid rdma_addr_unregister_client(struct rdma_addr_client *client) 107178784Skmacy{ 108178784Skmacy put_client(client); 109178784Skmacy mtx_lock(&client->lock); 110178784Skmacy if (client->refcount) { 111178784Skmacy cv_wait(&client->comp, &client->lock); 112178784Skmacy } 113178784Skmacy mtx_unlock(&client->lock); 114178784Skmacy} 115178784Skmacy 116178784Skmacyint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct ifnet *dev, 117178784Skmacy const unsigned char *dst_dev_addr) 118178784Skmacy{ 119178784Skmacy dev_addr->dev_type = RDMA_NODE_RNIC; 120252555Snp memset(dev_addr->src_dev_addr, 0, MAX_ADDR_LEN); 121252555Snp memcpy(dev_addr->src_dev_addr, IF_LLADDR(dev), dev->if_addrlen); 122178784Skmacy memcpy(dev_addr->broadcast, dev->if_broadcastaddr, MAX_ADDR_LEN); 123178784Skmacy if (dst_dev_addr) 124178784Skmacy memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN); 125178784Skmacy return 0; 126178784Skmacy} 127178784Skmacy 128178784Skmacyint rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) 129178784Skmacy{ 130178784Skmacy struct ifaddr *ifa; 131178784Skmacy struct sockaddr_in *sin = (struct sockaddr_in *)addr; 132178784Skmacy uint16_t port = sin->sin_port; 133194760Srwatson int ret; 134178784Skmacy 135178784Skmacy sin->sin_port = 0; 136178784Skmacy ifa = ifa_ifwithaddr(addr); 137178784Skmacy sin->sin_port = port; 138178784Skmacy if (!ifa) 139178784Skmacy return (EADDRNOTAVAIL); 140194760Srwatson ret = rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL); 141194760Srwatson ifa_free(ifa); 142194760Srwatson return (ret); 143178784Skmacy} 144178784Skmacy 145178784Skmacystatic void queue_req(struct addr_req *req) 146178784Skmacy{ 147178784Skmacy struct addr_req *tmp_req = NULL; 148178784Skmacy 149178784Skmacy mtx_lock(&lock); 150178784Skmacy TAILQ_FOREACH_REVERSE(tmp_req, &req_list, addr_req_list, entry) 151178784Skmacy if (time_after_eq(req->timeout, tmp_req->timeout)) 152178784Skmacy break; 153178784Skmacy 154178784Skmacy if (tmp_req) 155178784Skmacy TAILQ_INSERT_AFTER(&req_list, tmp_req, req, entry); 156178784Skmacy else 157178784Skmacy TAILQ_INSERT_TAIL(&req_list, req, entry); 158178784Skmacy 159178784Skmacy if (TAILQ_FIRST(&req_list) == req) 160178784Skmacy callout_reset(&addr_ch, req->timeout - ticks, addr_timeout, NULL); 161178784Skmacy mtx_unlock(&lock); 162178784Skmacy} 163178784Skmacy 164178784Skmacy#ifdef needed 165178784Skmacystatic void addr_send_arp(struct sockaddr_in *dst_in) 166178784Skmacy{ 167178784Skmacy struct route iproute; 168178784Skmacy struct sockaddr_in *dst = (struct sockaddr_in *)&iproute.ro_dst; 169178784Skmacy char dmac[ETHER_ADDR_LEN]; 170186119Sqingli struct llentry *lle; 171178784Skmacy 172178784Skmacy bzero(&iproute, sizeof iproute); 173178784Skmacy *dst = *dst_in; 174178784Skmacy 175178784Skmacy rtalloc(&iproute); 176178784Skmacy if (iproute.ro_rt == NULL); 177178784Skmacy return; 178178784Skmacy 179178784Skmacy arpresolve(iproute.ro_rt->rt_ifp, iproute.ro_rt, NULL, 180186119Sqingli rt_key(iproute.ro_rt), dmac, &lle); 181178784Skmacy 182178784Skmacy RTFREE(iproute.ro_rt); 183178784Skmacy} 184178784Skmacy#endif 185178784Skmacy 186178784Skmacystatic int addr_resolve_remote(struct sockaddr_in *src_in, 187178784Skmacy struct sockaddr_in *dst_in, 188178784Skmacy struct rdma_dev_addr *addr) 189178784Skmacy{ 190178784Skmacy int ret = 0; 191178784Skmacy struct route iproute; 192178784Skmacy struct sockaddr_in *dst = (struct sockaddr_in *)&iproute.ro_dst; 193178784Skmacy char dmac[ETHER_ADDR_LEN]; 194186119Sqingli struct llentry *lle; 195178784Skmacy 196178784Skmacy bzero(&iproute, sizeof iproute); 197178784Skmacy *dst = *dst_in; 198178784Skmacy 199178784Skmacy rtalloc(&iproute); 200178784Skmacy if (iproute.ro_rt == NULL) { 201178784Skmacy ret = EHOSTUNREACH; 202178784Skmacy goto out; 203178784Skmacy } 204178784Skmacy 205178784Skmacy /* If the device does ARP internally, return 'done' */ 206178784Skmacy if (iproute.ro_rt->rt_ifp->if_flags & IFF_NOARP) { 207178784Skmacy rdma_copy_addr(addr, iproute.ro_rt->rt_ifp, NULL); 208178784Skmacy goto put; 209178784Skmacy } 210178784Skmacy ret = arpresolve(iproute.ro_rt->rt_ifp, iproute.ro_rt, NULL, 211252555Snp (struct sockaddr *)dst_in, dmac, &lle); 212178784Skmacy if (ret) { 213178784Skmacy goto put; 214178784Skmacy } 215178784Skmacy 216178784Skmacy if (!src_in->sin_addr.s_addr) { 217178784Skmacy src_in->sin_len = sizeof *src_in; 218178784Skmacy src_in->sin_family = dst_in->sin_family; 219178784Skmacy src_in->sin_addr.s_addr = ((struct sockaddr_in *)iproute.ro_rt->rt_ifa->ifa_addr)->sin_addr.s_addr; 220178784Skmacy } 221178784Skmacy 222178784Skmacy ret = rdma_copy_addr(addr, iproute.ro_rt->rt_ifp, dmac); 223178784Skmacyput: 224178784Skmacy RTFREE(iproute.ro_rt); 225178784Skmacyout: 226178784Skmacy return ret; 227178784Skmacy} 228178784Skmacy 229178784Skmacystatic void process_req(void *ctx, int pending) 230178784Skmacy{ 231178784Skmacy struct addr_req *req, *tmp_req; 232178784Skmacy struct sockaddr_in *src_in, *dst_in; 233178784Skmacy TAILQ_HEAD(, addr_req) done_list; 234178784Skmacy 235178784Skmacy TAILQ_INIT(&done_list); 236178784Skmacy 237178784Skmacy mtx_lock(&lock); 238178784Skmacy TAILQ_FOREACH_SAFE(req, &req_list, entry, tmp_req) { 239178784Skmacy if (req->status == EWOULDBLOCK) { 240178784Skmacy src_in = (struct sockaddr_in *) &req->src_addr; 241178784Skmacy dst_in = (struct sockaddr_in *) &req->dst_addr; 242178784Skmacy req->status = addr_resolve_remote(src_in, dst_in, 243178784Skmacy req->addr); 244178784Skmacy if (req->status && time_after_eq(ticks, req->timeout)) 245178784Skmacy req->status = ETIMEDOUT; 246178784Skmacy else if (req->status == EWOULDBLOCK) 247178784Skmacy continue; 248178784Skmacy } 249178784Skmacy TAILQ_REMOVE(&req_list, req, entry); 250178784Skmacy TAILQ_INSERT_TAIL(&done_list, req, entry); 251178784Skmacy } 252178784Skmacy 253178784Skmacy if (!TAILQ_EMPTY(&req_list)) { 254178784Skmacy req = TAILQ_FIRST(&req_list); 255178784Skmacy callout_reset(&addr_ch, req->timeout - ticks, addr_timeout, 256178784Skmacy NULL); 257178784Skmacy } 258178784Skmacy mtx_unlock(&lock); 259178784Skmacy 260178784Skmacy TAILQ_FOREACH_SAFE(req, &done_list, entry, tmp_req) { 261178784Skmacy TAILQ_REMOVE(&done_list, req, entry); 262178784Skmacy req->callback(req->status, &req->src_addr, req->addr, 263178784Skmacy req->context); 264178784Skmacy put_client(req->client); 265178784Skmacy free(req, M_DEVBUF); 266178784Skmacy } 267178784Skmacy} 268178784Skmacy 269178784Skmacyint rdma_resolve_ip(struct rdma_addr_client *client, 270178784Skmacy struct sockaddr *src_addr, struct sockaddr *dst_addr, 271178784Skmacy struct rdma_dev_addr *addr, int timeout_ms, 272178784Skmacy void (*callback)(int status, struct sockaddr *src_addr, 273178784Skmacy struct rdma_dev_addr *addr, void *context), 274178784Skmacy void *context) 275178784Skmacy{ 276178784Skmacy struct sockaddr_in *src_in, *dst_in; 277178784Skmacy struct addr_req *req; 278178784Skmacy int ret = 0; 279178784Skmacy 280178784Skmacy req = malloc(sizeof *req, M_DEVBUF, M_NOWAIT); 281178784Skmacy if (!req) 282178784Skmacy return (ENOMEM); 283178784Skmacy memset(req, 0, sizeof *req); 284178784Skmacy 285178784Skmacy if (src_addr) 286178784Skmacy memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr)); 287178784Skmacy memcpy(&req->dst_addr, dst_addr, ip_addr_size(dst_addr)); 288178784Skmacy req->addr = addr; 289178784Skmacy req->callback = callback; 290178784Skmacy req->context = context; 291178784Skmacy req->client = client; 292178784Skmacy mtx_lock(&client->lock); 293178784Skmacy client->refcount++; 294178784Skmacy mtx_unlock(&client->lock); 295178784Skmacy 296178784Skmacy src_in = (struct sockaddr_in *) &req->src_addr; 297178784Skmacy dst_in = (struct sockaddr_in *) &req->dst_addr; 298178784Skmacy 299178784Skmacy req->status = addr_resolve_remote(src_in, dst_in, addr); 300178784Skmacy 301178784Skmacy switch (req->status) { 302178784Skmacy case 0: 303178784Skmacy req->timeout = ticks; 304178784Skmacy queue_req(req); 305178784Skmacy break; 306178784Skmacy case EWOULDBLOCK: 307178784Skmacy req->timeout = msecs_to_ticks(timeout_ms) + ticks; 308178784Skmacy queue_req(req); 309178784Skmacy#ifdef needed 310178784Skmacy addr_send_arp(dst_in); 311178784Skmacy#endif 312178784Skmacy break; 313178784Skmacy default: 314178784Skmacy ret = req->status; 315178784Skmacy mtx_lock(&client->lock); 316178784Skmacy client->refcount--; 317178784Skmacy mtx_unlock(&client->lock); 318178784Skmacy free(req, M_DEVBUF); 319178784Skmacy break; 320178784Skmacy } 321178784Skmacy return ret; 322178784Skmacy} 323178784Skmacy 324178784Skmacyvoid rdma_addr_cancel(struct rdma_dev_addr *addr) 325178784Skmacy{ 326178784Skmacy struct addr_req *req, *tmp_req; 327178784Skmacy 328178784Skmacy mtx_lock(&lock); 329178784Skmacy TAILQ_FOREACH_SAFE(req, &req_list, entry, tmp_req) { 330178784Skmacy if (req->addr == addr) { 331178784Skmacy req->status = ECANCELED; 332178784Skmacy req->timeout = ticks; 333178784Skmacy TAILQ_REMOVE(&req_list, req, entry); 334178784Skmacy TAILQ_INSERT_HEAD(&req_list, req, entry); 335178784Skmacy callout_reset(&addr_ch, req->timeout - ticks, addr_timeout, NULL); 336178784Skmacy break; 337178784Skmacy } 338178784Skmacy } 339178784Skmacy mtx_unlock(&lock); 340178784Skmacy} 341178784Skmacy 342178784Skmacystatic void 343178784Skmacyroute_event_arp_update(void *unused, struct rtentry *rt0, uint8_t *enaddr, 344178784Skmacy struct sockaddr *sa) 345178784Skmacy{ 346178784Skmacy callout_stop(&addr_ch); 347178784Skmacy taskqueue_enqueue(addr_taskq, &addr_task); 348178784Skmacy} 349178784Skmacy 350178784Skmacystatic int addr_init(void) 351178784Skmacy{ 352178784Skmacy TAILQ_INIT(&req_list); 353178784Skmacy mtx_init(&lock, "rdma_addr req_list lock", NULL, MTX_DEF); 354178784Skmacy 355178784Skmacy addr_taskq = taskqueue_create("rdma_addr_taskq", M_NOWAIT, 356178784Skmacy taskqueue_thread_enqueue, &addr_taskq); 357178784Skmacy if (addr_taskq == NULL) { 358178784Skmacy printf("failed to allocate rdma_addr taskqueue\n"); 359178784Skmacy return (ENOMEM); 360178784Skmacy } 361178784Skmacy taskqueue_start_threads(&addr_taskq, 1, PI_NET, "rdma_addr taskq"); 362178784Skmacy TASK_INIT(&addr_task, 0, process_req, NULL); 363178784Skmacy 364178784Skmacy callout_init(&addr_ch, TRUE); 365178784Skmacy 366178784Skmacy route_event_tag = EVENTHANDLER_REGISTER(route_arp_update_event, 367178784Skmacy route_event_arp_update, NULL, EVENTHANDLER_PRI_ANY); 368178784Skmacy 369178784Skmacy return 0; 370178784Skmacy} 371178784Skmacy 372178784Skmacystatic void addr_cleanup(void) 373178784Skmacy{ 374178784Skmacy EVENTHANDLER_DEREGISTER(route_event_arp_update, route_event_tag); 375178784Skmacy callout_stop(&addr_ch); 376178784Skmacy taskqueue_drain(addr_taskq, &addr_task); 377178784Skmacy taskqueue_free(addr_taskq); 378178784Skmacy} 379178784Skmacy 380178784Skmacystatic int 381178784Skmacyaddr_load(module_t mod, int cmd, void *arg) 382178784Skmacy{ 383178784Skmacy int err = 0; 384178784Skmacy 385178784Skmacy switch (cmd) { 386178784Skmacy case MOD_LOAD: 387178784Skmacy printf("Loading rdma_addr.\n"); 388178784Skmacy 389178784Skmacy addr_init(); 390178784Skmacy break; 391178784Skmacy case MOD_QUIESCE: 392178784Skmacy break; 393178784Skmacy case MOD_UNLOAD: 394178784Skmacy printf("Unloading rdma_addr.\n"); 395178784Skmacy addr_cleanup(); 396178784Skmacy break; 397178784Skmacy case MOD_SHUTDOWN: 398178784Skmacy break; 399178784Skmacy default: 400178784Skmacy err = EOPNOTSUPP; 401178784Skmacy break; 402178784Skmacy } 403178784Skmacy 404178784Skmacy return (err); 405178784Skmacy} 406178784Skmacy 407178784Skmacystatic moduledata_t mod_data = { 408178784Skmacy "rdma_addr", 409178784Skmacy addr_load, 410178784Skmacy 0 411178784Skmacy}; 412178784Skmacy 413178784SkmacyMODULE_VERSION(rdma_addr, 1); 414178784SkmacyDECLARE_MODULE(rdma_addr, mod_data, SI_SUB_EXEC, SI_ORDER_ANY); 415