ib_addr.c revision 331769
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 available to you under a choice of one of two
8 * licenses.  You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
12 *
13 *     Redistribution and use in source and binary forms, with or
14 *     without modification, are permitted provided that the following
15 *     conditions are met:
16 *
17 *      - Redistributions of source code must retain the above
18 *        copyright notice, this list of conditions and the following
19 *        disclaimer.
20 *
21 *      - Redistributions in binary form must reproduce the above
22 *        copyright notice, this list of conditions and the following
23 *        disclaimer in the documentation and/or other materials
24 *        provided with the distribution.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE.
34 */
35
36#include <linux/mutex.h>
37#include <linux/inetdevice.h>
38#include <linux/slab.h>
39#include <linux/workqueue.h>
40#include <linux/module.h>
41#include <net/route.h>
42#include <net/netevent.h>
43#include <rdma/ib_addr.h>
44#include <rdma/ib.h>
45
46#include <netinet/if_ether.h>
47#include <netinet/ip_var.h>
48#include <netinet6/scope6_var.h>
49#include <netinet6/in6_pcb.h>
50
51#include "core_priv.h"
52
53struct addr_req {
54	struct list_head list;
55	struct sockaddr_storage src_addr;
56	struct sockaddr_storage dst_addr;
57	struct rdma_dev_addr *addr;
58	struct rdma_addr_client *client;
59	void *context;
60	void (*callback)(int status, struct sockaddr *src_addr,
61			 struct rdma_dev_addr *addr, void *context);
62	unsigned long timeout;
63	int status;
64};
65
66static void process_req(struct work_struct *work);
67
68static DEFINE_MUTEX(lock);
69static LIST_HEAD(req_list);
70static DECLARE_DELAYED_WORK(work, process_req);
71static struct workqueue_struct *addr_wq;
72
73int rdma_addr_size(struct sockaddr *addr)
74{
75	switch (addr->sa_family) {
76	case AF_INET:
77		return sizeof(struct sockaddr_in);
78	case AF_INET6:
79		return sizeof(struct sockaddr_in6);
80	case AF_IB:
81		return sizeof(struct sockaddr_ib);
82	default:
83		return 0;
84	}
85}
86EXPORT_SYMBOL(rdma_addr_size);
87
88static struct rdma_addr_client self;
89
90void rdma_addr_register_client(struct rdma_addr_client *client)
91{
92	atomic_set(&client->refcount, 1);
93	init_completion(&client->comp);
94}
95EXPORT_SYMBOL(rdma_addr_register_client);
96
97static inline void put_client(struct rdma_addr_client *client)
98{
99	if (atomic_dec_and_test(&client->refcount))
100		complete(&client->comp);
101}
102
103void rdma_addr_unregister_client(struct rdma_addr_client *client)
104{
105	put_client(client);
106	wait_for_completion(&client->comp);
107}
108EXPORT_SYMBOL(rdma_addr_unregister_client);
109
110static inline void
111rdma_copy_addr_sub(u8 *dst, const u8 *src, unsigned min, unsigned max)
112{
113	if (min > max)
114		min = max;
115	memcpy(dst, src, min);
116	memset(dst + min, 0, max - min);
117}
118
119int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
120		     const unsigned char *dst_dev_addr)
121{
122	if (dev->if_type == IFT_INFINIBAND)
123		dev_addr->dev_type = ARPHRD_INFINIBAND;
124	else if (dev->if_type == IFT_ETHER)
125		dev_addr->dev_type = ARPHRD_ETHER;
126	else
127		dev_addr->dev_type = 0;
128	rdma_copy_addr_sub(dev_addr->src_dev_addr, IF_LLADDR(dev),
129			   dev->if_addrlen, MAX_ADDR_LEN);
130	rdma_copy_addr_sub(dev_addr->broadcast, dev->if_broadcastaddr,
131			   dev->if_addrlen, MAX_ADDR_LEN);
132	if (dst_dev_addr != NULL) {
133		rdma_copy_addr_sub(dev_addr->dst_dev_addr, dst_dev_addr,
134				   dev->if_addrlen, MAX_ADDR_LEN);
135	}
136	dev_addr->bound_dev_if = dev->if_index;
137	return 0;
138}
139EXPORT_SYMBOL(rdma_copy_addr);
140
141int rdma_translate_ip(const struct sockaddr *addr,
142		      struct rdma_dev_addr *dev_addr,
143		      u16 *vlan_id)
144{
145	struct net_device *dev = NULL;
146	int ret = -EADDRNOTAVAIL;
147
148	if (dev_addr->bound_dev_if) {
149		dev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if);
150		if (!dev)
151			return -ENODEV;
152		ret = rdma_copy_addr(dev_addr, dev, NULL);
153		dev_put(dev);
154		return ret;
155	}
156
157	switch (addr->sa_family) {
158#ifdef INET
159	case AF_INET:
160		dev = ip_dev_find(dev_addr->net,
161			((const struct sockaddr_in *)addr)->sin_addr.s_addr);
162		break;
163#endif
164#ifdef INET6
165	case AF_INET6:
166		dev = ip6_dev_find(dev_addr->net,
167			((const struct sockaddr_in6 *)addr)->sin6_addr);
168		break;
169#endif
170	default:
171		break;
172	}
173
174	if (dev != NULL) {
175		ret = rdma_copy_addr(dev_addr, dev, NULL);
176		if (vlan_id)
177			*vlan_id = rdma_vlan_dev_vlan_id(dev);
178		dev_put(dev);
179	}
180	return ret;
181}
182EXPORT_SYMBOL(rdma_translate_ip);
183
184static void set_timeout(unsigned long time)
185{
186	int delay;	/* under FreeBSD ticks are 32-bit */
187
188	delay = time - jiffies;
189	if (delay <= 0)
190		delay = 1;
191
192	mod_delayed_work(addr_wq, &work, delay);
193}
194
195static void queue_req(struct addr_req *req)
196{
197	struct addr_req *temp_req;
198
199	mutex_lock(&lock);
200	list_for_each_entry_reverse(temp_req, &req_list, list) {
201		if (time_after_eq(req->timeout, temp_req->timeout))
202			break;
203	}
204
205	list_add(&req->list, &temp_req->list);
206
207	if (req_list.next == &req->list)
208		set_timeout(req->timeout);
209	mutex_unlock(&lock);
210}
211
212#if defined(INET) || defined(INET6)
213static int addr_resolve_multi(u8 *edst, struct ifnet *ifp, struct sockaddr *dst_in)
214{
215	struct sockaddr *llsa;
216	struct sockaddr_dl sdl;
217	int error;
218
219	sdl.sdl_len = sizeof(sdl);
220	llsa = (struct sockaddr *)&sdl;
221
222	if (ifp->if_resolvemulti == NULL) {
223		error = EOPNOTSUPP;
224	} else {
225		error = ifp->if_resolvemulti(ifp, &llsa, dst_in);
226		if (error == 0) {
227			rdma_copy_addr_sub(edst, LLADDR((struct sockaddr_dl *)llsa),
228			    ifp->if_addrlen, MAX_ADDR_LEN);
229		}
230	}
231	return (error);
232}
233#endif
234
235#ifdef INET
236static int addr4_resolve(struct sockaddr_in *src_in,
237			 const struct sockaddr_in *dst_in,
238			 struct rdma_dev_addr *addr,
239			 struct ifnet **ifpp)
240{
241	struct sockaddr_in dst_tmp = *dst_in;
242	u8 edst[MAX_ADDR_LEN];
243	in_port_t src_port;
244	struct sockaddr *saddr;
245	struct rtentry *rte;
246	struct ifnet *ifp;
247	int error;
248	int type;
249
250	/* set VNET, if any */
251	CURVNET_SET(addr->net);
252
253	/* set default TTL limit */
254	addr->hoplimit = V_ip_defttl;
255
256	type = 0;
257	if (src_in->sin_addr.s_addr == INADDR_ANY)
258		type |= 1;
259	if (dst_tmp.sin_addr.s_addr == INADDR_ANY)
260		type |= 2;
261
262	/*
263	 * Make sure the socket address length field
264	 * is set, else rtalloc1() will fail.
265	 */
266	dst_tmp.sin_len = sizeof(dst_tmp);
267
268	/* Step 1 - lookup destination route if any */
269	switch (type) {
270	case 0:
271	case 1:
272		/* regular destination route lookup */
273		rte = rtalloc1((struct sockaddr *)&dst_tmp, 1, 0);
274		if (rte == NULL) {
275			error = EHOSTUNREACH;
276			goto done;
277		} else if (rte->rt_ifp == NULL || rte->rt_ifp == V_loif ||
278		    RT_LINK_IS_UP(rte->rt_ifp) == 0) {
279			RTFREE_LOCKED(rte);
280			error = EHOSTUNREACH;
281			goto done;
282		}
283		RT_UNLOCK(rte);
284		break;
285	default:
286		error = ENETUNREACH;
287		goto done;
288	}
289
290	/* Step 2 - find outgoing network interface */
291	switch (type) {
292	case 0:
293		/* source check */
294		ifp = ip_dev_find(addr->net, src_in->sin_addr.s_addr);
295		if (ifp == NULL) {
296			error = ENETUNREACH;
297			goto error_rt_free;
298		} else if (ifp != rte->rt_ifp) {
299			error = ENETUNREACH;
300			goto error_put_ifp;
301		}
302		break;
303	case 1:
304		/* get destination network interface from route */
305		ifp = rte->rt_ifp;
306		dev_hold(ifp);
307		saddr = rte->rt_ifa->ifa_addr;
308
309		src_port = src_in->sin_port;
310		memcpy(src_in, saddr, rdma_addr_size(saddr));
311		src_in->sin_port = src_port;	/* preserve port number */
312		break;
313	default:
314		break;
315	}
316
317	/*
318	 * Step 3 - resolve destination MAC address
319	 */
320	if (dst_tmp.sin_addr.s_addr == INADDR_BROADCAST) {
321		rdma_copy_addr_sub(edst, ifp->if_broadcastaddr,
322		    ifp->if_addrlen, MAX_ADDR_LEN);
323	} else if (IN_MULTICAST(ntohl(dst_tmp.sin_addr.s_addr))) {
324		error = addr_resolve_multi(edst, ifp, (struct sockaddr *)&dst_tmp);
325		if (error != 0)
326			goto error_put_ifp;
327	} else {
328		bool is_gw = (rte->rt_flags & RTF_GATEWAY) != 0;
329		memset(edst, 0, sizeof(edst));
330		error = arpresolve(ifp, is_gw, NULL, is_gw ?
331		    rte->rt_gateway : (const struct sockaddr *)&dst_tmp,
332		    edst, NULL, NULL);
333		if (error != 0)
334			goto error_put_ifp;
335		else if (is_gw != 0)
336			addr->network = RDMA_NETWORK_IPV4;
337	}
338
339	/*
340	 * Step 4 - copy destination and source MAC addresses
341	 */
342	error = -rdma_copy_addr(addr, ifp, edst);
343	if (error != 0)
344		goto error_put_ifp;
345
346	if (rte != NULL)
347		RTFREE(rte);
348
349	*ifpp = ifp;
350
351	goto done;
352
353error_put_ifp:
354	dev_put(ifp);
355error_rt_free:
356	RTFREE(rte);
357done:
358	CURVNET_RESTORE();
359
360	if (error == EWOULDBLOCK || error == EAGAIN)
361		error = ENODATA;
362	return (-error);
363}
364#else
365static int addr4_resolve(struct sockaddr_in *src_in,
366			 const struct sockaddr_in *dst_in,
367			 struct rdma_dev_addr *addr,
368			 struct ifnet **ifpp)
369{
370	return -EADDRNOTAVAIL;
371}
372#endif
373
374#ifdef INET6
375static int addr6_resolve(struct sockaddr_in6 *src_in,
376			 const struct sockaddr_in6 *dst_in,
377			 struct rdma_dev_addr *addr,
378			 struct ifnet **ifpp)
379{
380	struct sockaddr_in6 dst_tmp = *dst_in;
381	u8 edst[MAX_ADDR_LEN];
382	in_port_t src_port;
383	struct sockaddr *saddr;
384	struct rtentry *rte;
385	struct ifnet *ifp;
386	int error;
387	int type;
388
389	/* set VNET, if any */
390	CURVNET_SET(addr->net);
391
392	/* set default TTL limit */
393	addr->hoplimit = V_ip_defttl;
394
395	type = 0;
396	if (ipv6_addr_any(&src_in->sin6_addr))
397		type |= 1;
398	if (ipv6_addr_any(&dst_tmp.sin6_addr))
399		type |= 2;
400
401	/*
402	 * Make sure the socket address length field
403	 * is set, else rtalloc1() will fail.
404	 */
405	dst_tmp.sin6_len = sizeof(dst_tmp);
406
407	/* Step 1 - lookup destination route if any */
408	switch (type) {
409	case 0:
410		/* sanity check for IPv4 addresses */
411		if (ipv6_addr_v4mapped(&src_in->sin6_addr) !=
412		    ipv6_addr_v4mapped(&dst_tmp.sin6_addr)) {
413			error = EAFNOSUPPORT;
414			goto done;
415		}
416		/* FALLTHROUGH */
417	case 1:
418		/* regular destination route lookup */
419		rte = rtalloc1((struct sockaddr *)&dst_tmp, 1, 0);
420		if (rte == NULL) {
421			error = EHOSTUNREACH;
422			goto done;
423		} else if (rte->rt_ifp == NULL || rte->rt_ifp == V_loif ||
424		    RT_LINK_IS_UP(rte->rt_ifp) == 0) {
425			RTFREE_LOCKED(rte);
426			error = EHOSTUNREACH;
427			goto done;
428		}
429		RT_UNLOCK(rte);
430		break;
431	default:
432		error = ENETUNREACH;
433		goto done;
434	}
435
436	/* Step 2 - find outgoing network interface */
437	switch (type) {
438	case 0:
439		/* source check */
440		ifp = ip6_dev_find(addr->net, src_in->sin6_addr);
441		if (ifp == NULL) {
442			error = ENETUNREACH;
443			goto error_rt_free;
444		} else if (ifp != rte->rt_ifp) {
445			error = ENETUNREACH;
446			goto error_put_ifp;
447		}
448		break;
449	case 1:
450		/* get destination network interface from route */
451		ifp = rte->rt_ifp;
452		dev_hold(ifp);
453		saddr = rte->rt_ifa->ifa_addr;
454
455		src_port = src_in->sin6_port;
456		memcpy(src_in, saddr, rdma_addr_size(saddr));
457		src_in->sin6_port = src_port;	/* preserve port number */
458		break;
459	default:
460		break;
461	}
462
463	/*
464	 * Step 3 - resolve destination MAC address
465	 */
466	if (IN6_IS_ADDR_MULTICAST(&dst_tmp.sin6_addr)) {
467		error = addr_resolve_multi(edst, ifp,
468		    (struct sockaddr *)&dst_tmp);
469		if (error != 0)
470			goto error_put_ifp;
471	} else {
472		bool is_gw = (rte->rt_flags & RTF_GATEWAY) != 0;
473		memset(edst, 0, sizeof(edst));
474		error = nd6_resolve(ifp, is_gw, NULL, is_gw ?
475		    rte->rt_gateway : (const struct sockaddr *)&dst_tmp,
476		    edst, NULL, NULL);
477		if (error != 0)
478			goto error_put_ifp;
479		else if (is_gw != 0)
480			addr->network = RDMA_NETWORK_IPV6;
481	}
482
483	/*
484	 * Step 4 - copy destination and source MAC addresses
485	 */
486	error = -rdma_copy_addr(addr, ifp, edst);
487	if (error != 0)
488		goto error_put_ifp;
489
490	if (rte != NULL)
491		RTFREE(rte);
492
493	*ifpp = ifp;
494
495	goto done;
496
497error_put_ifp:
498	dev_put(ifp);
499error_rt_free:
500	RTFREE(rte);
501done:
502	CURVNET_RESTORE();
503
504	if (error == EWOULDBLOCK || error == EAGAIN)
505		error = ENODATA;
506	return (-error);
507}
508#else
509static int addr6_resolve(struct sockaddr_in6 *src_in,
510			 const struct sockaddr_in6 *dst_in,
511			 struct rdma_dev_addr *addr,
512			 struct ifnet **ifpp)
513{
514	return -EADDRNOTAVAIL;
515}
516#endif
517
518static int addr_resolve_neigh(struct ifnet *dev,
519			      const struct sockaddr *dst_in,
520			      struct rdma_dev_addr *addr)
521{
522	if (dev->if_flags & IFF_LOOPBACK) {
523		int ret;
524
525		ret = rdma_translate_ip(dst_in, addr, NULL);
526		if (!ret)
527			memcpy(addr->dst_dev_addr, addr->src_dev_addr,
528			       MAX_ADDR_LEN);
529
530		return ret;
531	}
532
533	/* If the device doesn't do ARP internally */
534	if (!(dev->if_flags & IFF_NOARP))
535		return 0;
536
537	return rdma_copy_addr(addr, dev, NULL);
538}
539
540static int addr_resolve(struct sockaddr *src_in,
541			const struct sockaddr *dst_in,
542			struct rdma_dev_addr *addr,
543			bool resolve_neigh)
544{
545	struct net_device *ndev = NULL;
546	int ret;
547
548	if (dst_in->sa_family != src_in->sa_family)
549		return -EINVAL;
550
551	if (src_in->sa_family == AF_INET) {
552		ret = addr4_resolve((struct sockaddr_in *)src_in,
553				    (const struct sockaddr_in *)dst_in,
554				    addr, &ndev);
555		if (ret)
556			return ret;
557
558		if (resolve_neigh)
559			ret = addr_resolve_neigh(ndev, dst_in, addr);
560	} else {
561		ret = addr6_resolve((struct sockaddr_in6 *)src_in,
562				    (const struct sockaddr_in6 *)dst_in, addr,
563				    &ndev);
564		if (ret)
565			return ret;
566
567		if (resolve_neigh)
568			ret = addr_resolve_neigh(ndev, dst_in, addr);
569	}
570
571	addr->bound_dev_if = ndev->if_index;
572	addr->net = dev_net(ndev);
573	dev_put(ndev);
574
575	return ret;
576}
577
578static void process_req(struct work_struct *work)
579{
580	struct addr_req *req, *temp_req;
581	struct sockaddr *src_in, *dst_in;
582	struct list_head done_list;
583
584	INIT_LIST_HEAD(&done_list);
585
586	mutex_lock(&lock);
587	list_for_each_entry_safe(req, temp_req, &req_list, list) {
588		if (req->status == -ENODATA) {
589			src_in = (struct sockaddr *) &req->src_addr;
590			dst_in = (struct sockaddr *) &req->dst_addr;
591			req->status = addr_resolve(src_in, dst_in, req->addr,
592						   true);
593			if (req->status && time_after_eq(jiffies, req->timeout))
594				req->status = -ETIMEDOUT;
595			else if (req->status == -ENODATA)
596				continue;
597		}
598		list_move_tail(&req->list, &done_list);
599	}
600
601	if (!list_empty(&req_list)) {
602		req = list_entry(req_list.next, struct addr_req, list);
603		set_timeout(req->timeout);
604	}
605	mutex_unlock(&lock);
606
607	list_for_each_entry_safe(req, temp_req, &done_list, list) {
608		list_del(&req->list);
609		req->callback(req->status, (struct sockaddr *) &req->src_addr,
610			req->addr, req->context);
611		put_client(req->client);
612		kfree(req);
613	}
614}
615
616int rdma_resolve_ip(struct rdma_addr_client *client,
617		    struct sockaddr *src_addr, struct sockaddr *dst_addr,
618		    struct rdma_dev_addr *addr, int timeout_ms,
619		    void (*callback)(int status, struct sockaddr *src_addr,
620				     struct rdma_dev_addr *addr, void *context),
621		    void *context)
622{
623	struct sockaddr *src_in, *dst_in;
624	struct addr_req *req;
625	int ret = 0;
626
627	req = kzalloc(sizeof *req, GFP_KERNEL);
628	if (!req)
629		return -ENOMEM;
630
631	src_in = (struct sockaddr *) &req->src_addr;
632	dst_in = (struct sockaddr *) &req->dst_addr;
633
634	if (src_addr) {
635		if (src_addr->sa_family != dst_addr->sa_family) {
636			ret = -EINVAL;
637			goto err;
638		}
639
640		memcpy(src_in, src_addr, rdma_addr_size(src_addr));
641	} else {
642		src_in->sa_family = dst_addr->sa_family;
643	}
644
645	memcpy(dst_in, dst_addr, rdma_addr_size(dst_addr));
646	req->addr = addr;
647	req->callback = callback;
648	req->context = context;
649	req->client = client;
650	atomic_inc(&client->refcount);
651
652	req->status = addr_resolve(src_in, dst_in, addr, true);
653	switch (req->status) {
654	case 0:
655		req->timeout = jiffies;
656		queue_req(req);
657		break;
658	case -ENODATA:
659		req->timeout = msecs_to_jiffies(timeout_ms) + jiffies;
660		queue_req(req);
661		break;
662	default:
663		ret = req->status;
664		atomic_dec(&client->refcount);
665		goto err;
666	}
667	return ret;
668err:
669	kfree(req);
670	return ret;
671}
672EXPORT_SYMBOL(rdma_resolve_ip);
673
674int rdma_resolve_ip_route(struct sockaddr *src_addr,
675			  const struct sockaddr *dst_addr,
676			  struct rdma_dev_addr *addr)
677{
678	struct sockaddr_storage ssrc_addr = {};
679	struct sockaddr *src_in = (struct sockaddr *)&ssrc_addr;
680
681	if (src_addr) {
682		if (src_addr->sa_family != dst_addr->sa_family)
683			return -EINVAL;
684
685		memcpy(src_in, src_addr, rdma_addr_size(src_addr));
686	} else {
687		src_in->sa_family = dst_addr->sa_family;
688	}
689
690	return addr_resolve(src_in, dst_addr, addr, false);
691}
692EXPORT_SYMBOL(rdma_resolve_ip_route);
693
694void rdma_addr_cancel(struct rdma_dev_addr *addr)
695{
696	struct addr_req *req, *temp_req;
697
698	mutex_lock(&lock);
699	list_for_each_entry_safe(req, temp_req, &req_list, list) {
700		if (req->addr == addr) {
701			req->status = -ECANCELED;
702			req->timeout = jiffies;
703			list_move(&req->list, &req_list);
704			set_timeout(req->timeout);
705			break;
706		}
707	}
708	mutex_unlock(&lock);
709}
710EXPORT_SYMBOL(rdma_addr_cancel);
711
712struct resolve_cb_context {
713	struct rdma_dev_addr *addr;
714	struct completion comp;
715	int status;
716};
717
718static void resolve_cb(int status, struct sockaddr *src_addr,
719	     struct rdma_dev_addr *addr, void *context)
720{
721	if (!status)
722		memcpy(((struct resolve_cb_context *)context)->addr,
723		       addr, sizeof(struct rdma_dev_addr));
724	((struct resolve_cb_context *)context)->status = status;
725	complete(&((struct resolve_cb_context *)context)->comp);
726}
727
728int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
729				 const union ib_gid *dgid,
730				 u8 *dmac, u16 *vlan_id, int *if_index,
731				 int *hoplimit)
732{
733	int ret = 0;
734	struct rdma_dev_addr dev_addr;
735	struct resolve_cb_context ctx;
736	struct net_device *dev;
737
738	union {
739		struct sockaddr     _sockaddr;
740		struct sockaddr_in  _sockaddr_in;
741		struct sockaddr_in6 _sockaddr_in6;
742	} sgid_addr, dgid_addr;
743
744
745	rdma_gid2ip(&sgid_addr._sockaddr, sgid);
746	rdma_gid2ip(&dgid_addr._sockaddr, dgid);
747
748	memset(&dev_addr, 0, sizeof(dev_addr));
749	if (if_index)
750		dev_addr.bound_dev_if = *if_index;
751	dev_addr.net = TD_TO_VNET(curthread);
752
753	ctx.addr = &dev_addr;
754	init_completion(&ctx.comp);
755	ret = rdma_resolve_ip(&self, &sgid_addr._sockaddr, &dgid_addr._sockaddr,
756			&dev_addr, 1000, resolve_cb, &ctx);
757	if (ret)
758		return ret;
759
760	wait_for_completion(&ctx.comp);
761
762	ret = ctx.status;
763	if (ret)
764		return ret;
765
766	memcpy(dmac, dev_addr.dst_dev_addr, ETH_ALEN);
767	dev = dev_get_by_index(dev_addr.net, dev_addr.bound_dev_if);
768	if (!dev)
769		return -ENODEV;
770	if (if_index)
771		*if_index = dev_addr.bound_dev_if;
772	if (vlan_id)
773		*vlan_id = rdma_vlan_dev_vlan_id(dev);
774	if (hoplimit)
775		*hoplimit = dev_addr.hoplimit;
776	dev_put(dev);
777	return ret;
778}
779EXPORT_SYMBOL(rdma_addr_find_l2_eth_by_grh);
780
781int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id)
782{
783	int ret = 0;
784	struct rdma_dev_addr dev_addr;
785	union {
786		struct sockaddr     _sockaddr;
787		struct sockaddr_in  _sockaddr_in;
788		struct sockaddr_in6 _sockaddr_in6;
789	} gid_addr;
790
791	rdma_gid2ip(&gid_addr._sockaddr, sgid);
792
793	memset(&dev_addr, 0, sizeof(dev_addr));
794	dev_addr.net = TD_TO_VNET(curthread);
795	ret = rdma_translate_ip(&gid_addr._sockaddr, &dev_addr, vlan_id);
796	if (ret)
797		return ret;
798
799	memcpy(smac, dev_addr.src_dev_addr, ETH_ALEN);
800	return ret;
801}
802EXPORT_SYMBOL(rdma_addr_find_smac_by_sgid);
803
804int addr_init(void)
805{
806	addr_wq = alloc_workqueue("ib_addr", WQ_MEM_RECLAIM, 0);
807	if (!addr_wq)
808		return -ENOMEM;
809
810	rdma_addr_register_client(&self);
811
812	return 0;
813}
814
815void addr_cleanup(void)
816{
817	rdma_addr_unregister_client(&self);
818	destroy_workqueue(addr_wq);
819}
820