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.
7 * This Software is licensed under one of the following licenses:
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.
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.
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.
21 * Licensee has the right to choose one of the above licenses.
23 * Redistributions of source code must retain the above copyright
24 * notice and one of the license notices.
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.
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
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>
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>
50 #include <net/if_dl.h>
51 #include <net/if_var.h>
52 #include <net/if_arp.h>
53 #include <net/route.h>
55 #include <net80211/ieee80211_freebsd.h>
57 #include <netinet/in.h>
58 #include <netinet/if_ether.h>
60 #include <contrib/rdma/ib_addr.h>
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;
69 void (*callback)(int status, struct sockaddr *src_addr,
70 struct rdma_dev_addr *addr, void *context);
71 unsigned long timeout;
75 static void process_req(void *ctx, int pending);
77 static struct mtx lock;
79 static TAILQ_HEAD(addr_req_list, addr_req) req_list;
80 static struct task addr_task;
81 static struct taskqueue *addr_taskq;
82 static struct callout addr_ch;
83 static eventhandler_tag route_event_tag;
85 static void addr_timeout(void *arg)
87 taskqueue_enqueue(addr_taskq, &addr_task);
90 void rdma_addr_register_client(struct rdma_addr_client *client)
92 mtx_init(&client->lock, "rdma_addr client lock", NULL, MTX_DUPOK|MTX_DEF);
93 cv_init(&client->comp, "rdma_addr cv");
97 static inline void put_client(struct rdma_addr_client *client)
99 mtx_lock(&client->lock);
100 if (--client->refcount == 0) {
101 cv_broadcast(&client->comp);
103 mtx_unlock(&client->lock);
106 void rdma_addr_unregister_client(struct rdma_addr_client *client)
109 mtx_lock(&client->lock);
110 if (client->refcount) {
111 cv_wait(&client->comp, &client->lock);
113 mtx_unlock(&client->lock);
116 int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct ifnet *dev,
117 const unsigned char *dst_dev_addr)
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);
124 memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN);
128 int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
131 struct sockaddr_in *sin = (struct sockaddr_in *)addr;
132 uint16_t port = sin->sin_port;
136 ifa = ifa_ifwithaddr(addr);
137 sin->sin_port = port;
139 return (EADDRNOTAVAIL);
140 ret = rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL);
145 static void queue_req(struct addr_req *req)
147 struct addr_req *tmp_req = NULL;
150 TAILQ_FOREACH_REVERSE(tmp_req, &req_list, addr_req_list, entry)
151 if (time_after_eq(req->timeout, tmp_req->timeout))
155 TAILQ_INSERT_AFTER(&req_list, tmp_req, req, entry);
157 TAILQ_INSERT_TAIL(&req_list, req, entry);
159 if (TAILQ_FIRST(&req_list) == req)
160 callout_reset(&addr_ch, req->timeout - ticks, addr_timeout, NULL);
165 static void addr_send_arp(struct sockaddr_in *dst_in)
167 struct route iproute;
168 struct sockaddr_in *dst = (struct sockaddr_in *)&iproute.ro_dst;
169 char dmac[ETHER_ADDR_LEN];
172 bzero(&iproute, sizeof iproute);
176 if (iproute.ro_rt == NULL);
179 arpresolve(iproute.ro_rt->rt_ifp, iproute.ro_rt, NULL,
180 rt_key(iproute.ro_rt), dmac, &lle);
182 RTFREE(iproute.ro_rt);
186 static int addr_resolve_remote(struct sockaddr_in *src_in,
187 struct sockaddr_in *dst_in,
188 struct rdma_dev_addr *addr)
191 struct route iproute;
192 struct sockaddr_in *dst = (struct sockaddr_in *)&iproute.ro_dst;
193 char dmac[ETHER_ADDR_LEN];
196 bzero(&iproute, sizeof iproute);
200 if (iproute.ro_rt == NULL) {
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);
210 ret = arpresolve(iproute.ro_rt->rt_ifp, iproute.ro_rt, NULL,
211 (struct sockaddr *)dst_in, dmac, &lle);
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;
222 ret = rdma_copy_addr(addr, iproute.ro_rt->rt_ifp, dmac);
224 RTFREE(iproute.ro_rt);
229 static void process_req(void *ctx, int pending)
231 struct addr_req *req, *tmp_req;
232 struct sockaddr_in *src_in, *dst_in;
233 TAILQ_HEAD(, addr_req) done_list;
235 TAILQ_INIT(&done_list);
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,
244 if (req->status && time_after_eq(ticks, req->timeout))
245 req->status = ETIMEDOUT;
246 else if (req->status == EWOULDBLOCK)
249 TAILQ_REMOVE(&req_list, req, entry);
250 TAILQ_INSERT_TAIL(&done_list, req, entry);
253 if (!TAILQ_EMPTY(&req_list)) {
254 req = TAILQ_FIRST(&req_list);
255 callout_reset(&addr_ch, req->timeout - ticks, addr_timeout,
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,
264 put_client(req->client);
269 int 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),
276 struct sockaddr_in *src_in, *dst_in;
277 struct addr_req *req;
280 req = malloc(sizeof *req, M_DEVBUF, M_NOWAIT);
283 memset(req, 0, sizeof *req);
286 memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr));
287 memcpy(&req->dst_addr, dst_addr, ip_addr_size(dst_addr));
289 req->callback = callback;
290 req->context = context;
291 req->client = client;
292 mtx_lock(&client->lock);
294 mtx_unlock(&client->lock);
296 src_in = (struct sockaddr_in *) &req->src_addr;
297 dst_in = (struct sockaddr_in *) &req->dst_addr;
299 req->status = addr_resolve_remote(src_in, dst_in, addr);
301 switch (req->status) {
303 req->timeout = ticks;
307 req->timeout = msecs_to_ticks(timeout_ms) + ticks;
310 addr_send_arp(dst_in);
315 mtx_lock(&client->lock);
317 mtx_unlock(&client->lock);
324 void rdma_addr_cancel(struct rdma_dev_addr *addr)
326 struct addr_req *req, *tmp_req;
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);
343 route_event_arp_update(void *unused, struct rtentry *rt0, uint8_t *enaddr,
346 callout_stop(&addr_ch);
347 taskqueue_enqueue(addr_taskq, &addr_task);
350 static int addr_init(void)
352 TAILQ_INIT(&req_list);
353 mtx_init(&lock, "rdma_addr req_list lock", NULL, MTX_DEF);
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");
361 taskqueue_start_threads(&addr_taskq, 1, PI_NET, "rdma_addr taskq");
362 TASK_INIT(&addr_task, 0, process_req, NULL);
364 callout_init(&addr_ch, TRUE);
366 route_event_tag = EVENTHANDLER_REGISTER(route_arp_update_event,
367 route_event_arp_update, NULL, EVENTHANDLER_PRI_ANY);
372 static void addr_cleanup(void)
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);
381 addr_load(module_t mod, int cmd, void *arg)
387 printf("Loading rdma_addr.\n");
394 printf("Unloading rdma_addr.\n");
407 static moduledata_t mod_data = {
413 MODULE_VERSION(rdma_addr, 1);
414 DECLARE_MODULE(rdma_addr, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);