1d6b92ffaSHans Petter Selasky /*
2d6b92ffaSHans Petter Selasky * Copyright (c) 2005 Topspin Communications. All rights reserved.
3d6b92ffaSHans Petter Selasky * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
4d6b92ffaSHans Petter Selasky *
5d6b92ffaSHans Petter Selasky * This software is available to you under a choice of one of two
6d6b92ffaSHans Petter Selasky * licenses. You may choose to be licensed under the terms of the GNU
7d6b92ffaSHans Petter Selasky * General Public License (GPL) Version 2, available from the file
8d6b92ffaSHans Petter Selasky * COPYING in the main directory of this source tree, or the
9d6b92ffaSHans Petter Selasky * OpenIB.org BSD license below:
10d6b92ffaSHans Petter Selasky *
11d6b92ffaSHans Petter Selasky * Redistribution and use in source and binary forms, with or
12d6b92ffaSHans Petter Selasky * without modification, are permitted provided that the following
13d6b92ffaSHans Petter Selasky * conditions are met:
14d6b92ffaSHans Petter Selasky *
15d6b92ffaSHans Petter Selasky * - Redistributions of source code must retain the above
16d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following
17d6b92ffaSHans Petter Selasky * disclaimer.
18d6b92ffaSHans Petter Selasky *
19d6b92ffaSHans Petter Selasky * - Redistributions in binary form must reproduce the above
20d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following
21d6b92ffaSHans Petter Selasky * disclaimer in the documentation and/or other materials
22d6b92ffaSHans Petter Selasky * provided with the distribution.
23d6b92ffaSHans Petter Selasky *
24d6b92ffaSHans Petter Selasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25d6b92ffaSHans Petter Selasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26d6b92ffaSHans Petter Selasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27d6b92ffaSHans Petter Selasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28d6b92ffaSHans Petter Selasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29d6b92ffaSHans Petter Selasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30d6b92ffaSHans Petter Selasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31d6b92ffaSHans Petter Selasky * SOFTWARE.
32d6b92ffaSHans Petter Selasky */
33d6b92ffaSHans Petter Selasky
34d6b92ffaSHans Petter Selasky #define _GNU_SOURCE
35d6b92ffaSHans Petter Selasky #include <config.h>
36d6b92ffaSHans Petter Selasky
37d6b92ffaSHans Petter Selasky #include <infiniband/endian.h>
38d6b92ffaSHans Petter Selasky #include <stdio.h>
39d6b92ffaSHans Petter Selasky #include <unistd.h>
40d6b92ffaSHans Petter Selasky #include <stdlib.h>
41d6b92ffaSHans Petter Selasky #include <errno.h>
42d6b92ffaSHans Petter Selasky #include <string.h>
43d6b92ffaSHans Petter Selasky #include <dirent.h>
44d6b92ffaSHans Petter Selasky #include <netinet/in.h>
45d6b92ffaSHans Petter Selasky #include <netinet/ip.h>
46d6b92ffaSHans Petter Selasky #include <sys/socket.h>
47d6b92ffaSHans Petter Selasky
48d6b92ffaSHans Petter Selasky #include "ibverbs.h"
49d6b92ffaSHans Petter Selasky #ifndef NRESOLVE_NEIGH
50d6b92ffaSHans Petter Selasky #include <net/if.h>
51d6b92ffaSHans Petter Selasky #include <net/if_arp.h>
52d6b92ffaSHans Petter Selasky #include "neigh.h"
53d6b92ffaSHans Petter Selasky #endif
54d6b92ffaSHans Petter Selasky
55d6b92ffaSHans Petter Selasky /* Hack to avoid GCC's -Wmissing-prototypes and the similar error from sparse
56d6b92ffaSHans Petter Selasky with these prototypes. Symbol versionining requires the goofy names, the
57d6b92ffaSHans Petter Selasky prototype must match the version in verbs.h.
58d6b92ffaSHans Petter Selasky */
59d6b92ffaSHans Petter Selasky int __ibv_query_device(struct ibv_context *context,
60d6b92ffaSHans Petter Selasky struct ibv_device_attr *device_attr);
61d6b92ffaSHans Petter Selasky int __ibv_query_port(struct ibv_context *context, uint8_t port_num,
62d6b92ffaSHans Petter Selasky struct ibv_port_attr *port_attr);
63d6b92ffaSHans Petter Selasky int __ibv_query_gid(struct ibv_context *context, uint8_t port_num, int index,
64d6b92ffaSHans Petter Selasky union ibv_gid *gid);
65d6b92ffaSHans Petter Selasky int __ibv_query_pkey(struct ibv_context *context, uint8_t port_num, int index,
66d6b92ffaSHans Petter Selasky __be16 *pkey);
67d6b92ffaSHans Petter Selasky struct ibv_pd *__ibv_alloc_pd(struct ibv_context *context);
68d6b92ffaSHans Petter Selasky int __ibv_dealloc_pd(struct ibv_pd *pd);
69d6b92ffaSHans Petter Selasky struct ibv_mr *__ibv_reg_mr(struct ibv_pd *pd, void *addr, size_t length,
70d6b92ffaSHans Petter Selasky int access);
71d6b92ffaSHans Petter Selasky int __ibv_rereg_mr(struct ibv_mr *mr, int flags, struct ibv_pd *pd, void *addr,
72d6b92ffaSHans Petter Selasky size_t length, int access);
73d6b92ffaSHans Petter Selasky int __ibv_dereg_mr(struct ibv_mr *mr);
74d6b92ffaSHans Petter Selasky struct ibv_cq *__ibv_create_cq(struct ibv_context *context, int cqe,
75d6b92ffaSHans Petter Selasky void *cq_context,
76d6b92ffaSHans Petter Selasky struct ibv_comp_channel *channel,
77d6b92ffaSHans Petter Selasky int comp_vector);
78d6b92ffaSHans Petter Selasky int __ibv_resize_cq(struct ibv_cq *cq, int cqe);
79d6b92ffaSHans Petter Selasky int __ibv_destroy_cq(struct ibv_cq *cq);
80d6b92ffaSHans Petter Selasky int __ibv_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq,
81d6b92ffaSHans Petter Selasky void **cq_context);
82d6b92ffaSHans Petter Selasky void __ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents);
83d6b92ffaSHans Petter Selasky struct ibv_srq *__ibv_create_srq(struct ibv_pd *pd,
84d6b92ffaSHans Petter Selasky struct ibv_srq_init_attr *srq_init_attr);
85d6b92ffaSHans Petter Selasky int __ibv_modify_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr,
86d6b92ffaSHans Petter Selasky int srq_attr_mask);
87d6b92ffaSHans Petter Selasky int __ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr);
88d6b92ffaSHans Petter Selasky int __ibv_destroy_srq(struct ibv_srq *srq);
89d6b92ffaSHans Petter Selasky struct ibv_qp *__ibv_create_qp(struct ibv_pd *pd,
90d6b92ffaSHans Petter Selasky struct ibv_qp_init_attr *qp_init_attr);
91d6b92ffaSHans Petter Selasky int __ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask,
92d6b92ffaSHans Petter Selasky struct ibv_qp_init_attr *init_attr);
93d6b92ffaSHans Petter Selasky int __ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask);
94d6b92ffaSHans Petter Selasky int __ibv_destroy_qp(struct ibv_qp *qp);
95d6b92ffaSHans Petter Selasky struct ibv_ah *__ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr);
96d6b92ffaSHans Petter Selasky int __ibv_destroy_ah(struct ibv_ah *ah);
97d6b92ffaSHans Petter Selasky int __ibv_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid,
98d6b92ffaSHans Petter Selasky uint16_t lid);
99d6b92ffaSHans Petter Selasky int __ibv_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid,
100d6b92ffaSHans Petter Selasky uint16_t lid);
101d6b92ffaSHans Petter Selasky
ibv_rate_to_mult(enum ibv_rate rate)102d6b92ffaSHans Petter Selasky int __attribute__((const)) ibv_rate_to_mult(enum ibv_rate rate)
103d6b92ffaSHans Petter Selasky {
104d6b92ffaSHans Petter Selasky switch (rate) {
105d6b92ffaSHans Petter Selasky case IBV_RATE_2_5_GBPS: return 1;
106d6b92ffaSHans Petter Selasky case IBV_RATE_5_GBPS: return 2;
107d6b92ffaSHans Petter Selasky case IBV_RATE_10_GBPS: return 4;
108d6b92ffaSHans Petter Selasky case IBV_RATE_20_GBPS: return 8;
109d6b92ffaSHans Petter Selasky case IBV_RATE_30_GBPS: return 12;
110d6b92ffaSHans Petter Selasky case IBV_RATE_40_GBPS: return 16;
111d6b92ffaSHans Petter Selasky case IBV_RATE_60_GBPS: return 24;
112d6b92ffaSHans Petter Selasky case IBV_RATE_80_GBPS: return 32;
113d6b92ffaSHans Petter Selasky case IBV_RATE_120_GBPS: return 48;
114daceb336SHans Petter Selasky case IBV_RATE_28_GBPS: return 11;
115daceb336SHans Petter Selasky case IBV_RATE_50_GBPS: return 20;
116daceb336SHans Petter Selasky case IBV_RATE_400_GBPS: return 160;
117daceb336SHans Petter Selasky case IBV_RATE_600_GBPS: return 240;
118d6b92ffaSHans Petter Selasky default: return -1;
119d6b92ffaSHans Petter Selasky }
120d6b92ffaSHans Petter Selasky }
121d6b92ffaSHans Petter Selasky
mult_to_ibv_rate(int mult)122d6b92ffaSHans Petter Selasky enum ibv_rate __attribute__((const)) mult_to_ibv_rate(int mult)
123d6b92ffaSHans Petter Selasky {
124d6b92ffaSHans Petter Selasky switch (mult) {
125d6b92ffaSHans Petter Selasky case 1: return IBV_RATE_2_5_GBPS;
126d6b92ffaSHans Petter Selasky case 2: return IBV_RATE_5_GBPS;
127d6b92ffaSHans Petter Selasky case 4: return IBV_RATE_10_GBPS;
128d6b92ffaSHans Petter Selasky case 8: return IBV_RATE_20_GBPS;
129d6b92ffaSHans Petter Selasky case 12: return IBV_RATE_30_GBPS;
130d6b92ffaSHans Petter Selasky case 16: return IBV_RATE_40_GBPS;
131d6b92ffaSHans Petter Selasky case 24: return IBV_RATE_60_GBPS;
132d6b92ffaSHans Petter Selasky case 32: return IBV_RATE_80_GBPS;
133d6b92ffaSHans Petter Selasky case 48: return IBV_RATE_120_GBPS;
134daceb336SHans Petter Selasky case 11: return IBV_RATE_28_GBPS;
135daceb336SHans Petter Selasky case 20: return IBV_RATE_50_GBPS;
136daceb336SHans Petter Selasky case 160: return IBV_RATE_400_GBPS;
137daceb336SHans Petter Selasky case 240: return IBV_RATE_600_GBPS;
138d6b92ffaSHans Petter Selasky default: return IBV_RATE_MAX;
139d6b92ffaSHans Petter Selasky }
140d6b92ffaSHans Petter Selasky }
141d6b92ffaSHans Petter Selasky
ibv_rate_to_mbps(enum ibv_rate rate)142d6b92ffaSHans Petter Selasky int __attribute__((const)) ibv_rate_to_mbps(enum ibv_rate rate)
143d6b92ffaSHans Petter Selasky {
144d6b92ffaSHans Petter Selasky switch (rate) {
145d6b92ffaSHans Petter Selasky case IBV_RATE_2_5_GBPS: return 2500;
146d6b92ffaSHans Petter Selasky case IBV_RATE_5_GBPS: return 5000;
147d6b92ffaSHans Petter Selasky case IBV_RATE_10_GBPS: return 10000;
148d6b92ffaSHans Petter Selasky case IBV_RATE_20_GBPS: return 20000;
149d6b92ffaSHans Petter Selasky case IBV_RATE_30_GBPS: return 30000;
150d6b92ffaSHans Petter Selasky case IBV_RATE_40_GBPS: return 40000;
151d6b92ffaSHans Petter Selasky case IBV_RATE_60_GBPS: return 60000;
152d6b92ffaSHans Petter Selasky case IBV_RATE_80_GBPS: return 80000;
153d6b92ffaSHans Petter Selasky case IBV_RATE_120_GBPS: return 120000;
154d6b92ffaSHans Petter Selasky case IBV_RATE_14_GBPS: return 14062;
155d6b92ffaSHans Petter Selasky case IBV_RATE_56_GBPS: return 56250;
156d6b92ffaSHans Petter Selasky case IBV_RATE_112_GBPS: return 112500;
157d6b92ffaSHans Petter Selasky case IBV_RATE_168_GBPS: return 168750;
158d6b92ffaSHans Petter Selasky case IBV_RATE_25_GBPS: return 25781;
159d6b92ffaSHans Petter Selasky case IBV_RATE_100_GBPS: return 103125;
160d6b92ffaSHans Petter Selasky case IBV_RATE_200_GBPS: return 206250;
161d6b92ffaSHans Petter Selasky case IBV_RATE_300_GBPS: return 309375;
162daceb336SHans Petter Selasky case IBV_RATE_28_GBPS: return 28125;
163daceb336SHans Petter Selasky case IBV_RATE_50_GBPS: return 53125;
164daceb336SHans Petter Selasky case IBV_RATE_400_GBPS: return 425000;
165daceb336SHans Petter Selasky case IBV_RATE_600_GBPS: return 637500;
166d6b92ffaSHans Petter Selasky default: return -1;
167d6b92ffaSHans Petter Selasky }
168d6b92ffaSHans Petter Selasky }
169d6b92ffaSHans Petter Selasky
mbps_to_ibv_rate(int mbps)170d6b92ffaSHans Petter Selasky enum ibv_rate __attribute__((const)) mbps_to_ibv_rate(int mbps)
171d6b92ffaSHans Petter Selasky {
172d6b92ffaSHans Petter Selasky switch (mbps) {
173d6b92ffaSHans Petter Selasky case 2500: return IBV_RATE_2_5_GBPS;
174d6b92ffaSHans Petter Selasky case 5000: return IBV_RATE_5_GBPS;
175d6b92ffaSHans Petter Selasky case 10000: return IBV_RATE_10_GBPS;
176d6b92ffaSHans Petter Selasky case 20000: return IBV_RATE_20_GBPS;
177d6b92ffaSHans Petter Selasky case 30000: return IBV_RATE_30_GBPS;
178d6b92ffaSHans Petter Selasky case 40000: return IBV_RATE_40_GBPS;
179d6b92ffaSHans Petter Selasky case 60000: return IBV_RATE_60_GBPS;
180d6b92ffaSHans Petter Selasky case 80000: return IBV_RATE_80_GBPS;
181d6b92ffaSHans Petter Selasky case 120000: return IBV_RATE_120_GBPS;
182d6b92ffaSHans Petter Selasky case 14062: return IBV_RATE_14_GBPS;
183d6b92ffaSHans Petter Selasky case 56250: return IBV_RATE_56_GBPS;
184d6b92ffaSHans Petter Selasky case 112500: return IBV_RATE_112_GBPS;
185d6b92ffaSHans Petter Selasky case 168750: return IBV_RATE_168_GBPS;
186d6b92ffaSHans Petter Selasky case 25781: return IBV_RATE_25_GBPS;
187d6b92ffaSHans Petter Selasky case 103125: return IBV_RATE_100_GBPS;
188d6b92ffaSHans Petter Selasky case 206250: return IBV_RATE_200_GBPS;
189d6b92ffaSHans Petter Selasky case 309375: return IBV_RATE_300_GBPS;
190daceb336SHans Petter Selasky case 28125: return IBV_RATE_28_GBPS;
191daceb336SHans Petter Selasky case 53125: return IBV_RATE_50_GBPS;
192daceb336SHans Petter Selasky case 425000: return IBV_RATE_400_GBPS;
193daceb336SHans Petter Selasky case 637500: return IBV_RATE_600_GBPS;
194d6b92ffaSHans Petter Selasky default: return IBV_RATE_MAX;
195d6b92ffaSHans Petter Selasky }
196d6b92ffaSHans Petter Selasky }
197d6b92ffaSHans Petter Selasky
__ibv_query_device(struct ibv_context * context,struct ibv_device_attr * device_attr)198d6b92ffaSHans Petter Selasky int __ibv_query_device(struct ibv_context *context,
199d6b92ffaSHans Petter Selasky struct ibv_device_attr *device_attr)
200d6b92ffaSHans Petter Selasky {
201d6b92ffaSHans Petter Selasky return context->ops.query_device(context, device_attr);
202d6b92ffaSHans Petter Selasky }
203d6b92ffaSHans Petter Selasky default_symver(__ibv_query_device, ibv_query_device);
204d6b92ffaSHans Petter Selasky
__ibv_query_port(struct ibv_context * context,uint8_t port_num,struct ibv_port_attr * port_attr)205d6b92ffaSHans Petter Selasky int __ibv_query_port(struct ibv_context *context, uint8_t port_num,
206d6b92ffaSHans Petter Selasky struct ibv_port_attr *port_attr)
207d6b92ffaSHans Petter Selasky {
208d6b92ffaSHans Petter Selasky return context->ops.query_port(context, port_num, port_attr);
209d6b92ffaSHans Petter Selasky }
210d6b92ffaSHans Petter Selasky default_symver(__ibv_query_port, ibv_query_port);
211d6b92ffaSHans Petter Selasky
__ibv_query_gid(struct ibv_context * context,uint8_t port_num,int index,union ibv_gid * gid)212d6b92ffaSHans Petter Selasky int __ibv_query_gid(struct ibv_context *context, uint8_t port_num,
213d6b92ffaSHans Petter Selasky int index, union ibv_gid *gid)
214d6b92ffaSHans Petter Selasky {
215d6b92ffaSHans Petter Selasky char name[24];
216d6b92ffaSHans Petter Selasky char attr[41];
217d6b92ffaSHans Petter Selasky uint16_t val;
218d6b92ffaSHans Petter Selasky int i;
219d6b92ffaSHans Petter Selasky
220d6b92ffaSHans Petter Selasky snprintf(name, sizeof name, "ports/%d/gids/%d", port_num, index);
221d6b92ffaSHans Petter Selasky
222d6b92ffaSHans Petter Selasky if (ibv_read_sysfs_file(context->device->ibdev_path, name,
223d6b92ffaSHans Petter Selasky attr, sizeof attr) < 0)
224d6b92ffaSHans Petter Selasky return -1;
225d6b92ffaSHans Petter Selasky
226d6b92ffaSHans Petter Selasky for (i = 0; i < 8; ++i) {
227d6b92ffaSHans Petter Selasky if (sscanf(attr + i * 5, "%hx", &val) != 1)
228d6b92ffaSHans Petter Selasky return -1;
229d6b92ffaSHans Petter Selasky gid->raw[i * 2 ] = val >> 8;
230d6b92ffaSHans Petter Selasky gid->raw[i * 2 + 1] = val & 0xff;
231d6b92ffaSHans Petter Selasky }
232d6b92ffaSHans Petter Selasky
233d6b92ffaSHans Petter Selasky return 0;
234d6b92ffaSHans Petter Selasky }
235d6b92ffaSHans Petter Selasky default_symver(__ibv_query_gid, ibv_query_gid);
236d6b92ffaSHans Petter Selasky
__ibv_query_pkey(struct ibv_context * context,uint8_t port_num,int index,__be16 * pkey)237d6b92ffaSHans Petter Selasky int __ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
238d6b92ffaSHans Petter Selasky int index, __be16 *pkey)
239d6b92ffaSHans Petter Selasky {
240d6b92ffaSHans Petter Selasky char name[24];
241d6b92ffaSHans Petter Selasky char attr[8];
242d6b92ffaSHans Petter Selasky uint16_t val;
243d6b92ffaSHans Petter Selasky
244d6b92ffaSHans Petter Selasky snprintf(name, sizeof name, "ports/%d/pkeys/%d", port_num, index);
245d6b92ffaSHans Petter Selasky
246d6b92ffaSHans Petter Selasky if (ibv_read_sysfs_file(context->device->ibdev_path, name,
247d6b92ffaSHans Petter Selasky attr, sizeof attr) < 0)
248d6b92ffaSHans Petter Selasky return -1;
249d6b92ffaSHans Petter Selasky
250d6b92ffaSHans Petter Selasky if (sscanf(attr, "%hx", &val) != 1)
251d6b92ffaSHans Petter Selasky return -1;
252d6b92ffaSHans Petter Selasky
253d6b92ffaSHans Petter Selasky *pkey = htobe16(val);
254d6b92ffaSHans Petter Selasky return 0;
255d6b92ffaSHans Petter Selasky }
256d6b92ffaSHans Petter Selasky default_symver(__ibv_query_pkey, ibv_query_pkey);
257d6b92ffaSHans Petter Selasky
__ibv_alloc_pd(struct ibv_context * context)258d6b92ffaSHans Petter Selasky struct ibv_pd *__ibv_alloc_pd(struct ibv_context *context)
259d6b92ffaSHans Petter Selasky {
260d6b92ffaSHans Petter Selasky struct ibv_pd *pd;
261d6b92ffaSHans Petter Selasky
262d6b92ffaSHans Petter Selasky pd = context->ops.alloc_pd(context);
263d6b92ffaSHans Petter Selasky if (pd)
264d6b92ffaSHans Petter Selasky pd->context = context;
265d6b92ffaSHans Petter Selasky
266d6b92ffaSHans Petter Selasky return pd;
267d6b92ffaSHans Petter Selasky }
268d6b92ffaSHans Petter Selasky default_symver(__ibv_alloc_pd, ibv_alloc_pd);
269d6b92ffaSHans Petter Selasky
__ibv_dealloc_pd(struct ibv_pd * pd)270d6b92ffaSHans Petter Selasky int __ibv_dealloc_pd(struct ibv_pd *pd)
271d6b92ffaSHans Petter Selasky {
272d6b92ffaSHans Petter Selasky return pd->context->ops.dealloc_pd(pd);
273d6b92ffaSHans Petter Selasky }
274d6b92ffaSHans Petter Selasky default_symver(__ibv_dealloc_pd, ibv_dealloc_pd);
275d6b92ffaSHans Petter Selasky
__ibv_reg_mr(struct ibv_pd * pd,void * addr,size_t length,int access)276d6b92ffaSHans Petter Selasky struct ibv_mr *__ibv_reg_mr(struct ibv_pd *pd, void *addr,
277d6b92ffaSHans Petter Selasky size_t length, int access)
278d6b92ffaSHans Petter Selasky {
279d6b92ffaSHans Petter Selasky struct ibv_mr *mr;
280d6b92ffaSHans Petter Selasky
281d6b92ffaSHans Petter Selasky if (ibv_dontfork_range(addr, length))
282d6b92ffaSHans Petter Selasky return NULL;
283d6b92ffaSHans Petter Selasky
284d6b92ffaSHans Petter Selasky mr = pd->context->ops.reg_mr(pd, addr, length, access);
285d6b92ffaSHans Petter Selasky if (mr) {
286d6b92ffaSHans Petter Selasky mr->context = pd->context;
287d6b92ffaSHans Petter Selasky mr->pd = pd;
288d6b92ffaSHans Petter Selasky mr->addr = addr;
289d6b92ffaSHans Petter Selasky mr->length = length;
290d6b92ffaSHans Petter Selasky } else
291d6b92ffaSHans Petter Selasky ibv_dofork_range(addr, length);
292d6b92ffaSHans Petter Selasky
293d6b92ffaSHans Petter Selasky return mr;
294d6b92ffaSHans Petter Selasky }
295d6b92ffaSHans Petter Selasky default_symver(__ibv_reg_mr, ibv_reg_mr);
296d6b92ffaSHans Petter Selasky
__ibv_rereg_mr(struct ibv_mr * mr,int flags,struct ibv_pd * pd,void * addr,size_t length,int access)297d6b92ffaSHans Petter Selasky int __ibv_rereg_mr(struct ibv_mr *mr, int flags,
298d6b92ffaSHans Petter Selasky struct ibv_pd *pd, void *addr,
299d6b92ffaSHans Petter Selasky size_t length, int access)
300d6b92ffaSHans Petter Selasky {
301d6b92ffaSHans Petter Selasky int dofork_onfail = 0;
302d6b92ffaSHans Petter Selasky int err;
303d6b92ffaSHans Petter Selasky void *old_addr;
304d6b92ffaSHans Petter Selasky size_t old_len;
305d6b92ffaSHans Petter Selasky
306d6b92ffaSHans Petter Selasky if (flags & ~IBV_REREG_MR_FLAGS_SUPPORTED) {
307d6b92ffaSHans Petter Selasky errno = EINVAL;
308d6b92ffaSHans Petter Selasky return IBV_REREG_MR_ERR_INPUT;
309d6b92ffaSHans Petter Selasky }
310d6b92ffaSHans Petter Selasky
311d6b92ffaSHans Petter Selasky if ((flags & IBV_REREG_MR_CHANGE_TRANSLATION) &&
312d6b92ffaSHans Petter Selasky (!length || !addr)) {
313d6b92ffaSHans Petter Selasky errno = EINVAL;
314d6b92ffaSHans Petter Selasky return IBV_REREG_MR_ERR_INPUT;
315d6b92ffaSHans Petter Selasky }
316d6b92ffaSHans Petter Selasky
317d6b92ffaSHans Petter Selasky if (access && !(flags & IBV_REREG_MR_CHANGE_ACCESS)) {
318d6b92ffaSHans Petter Selasky errno = EINVAL;
319d6b92ffaSHans Petter Selasky return IBV_REREG_MR_ERR_INPUT;
320d6b92ffaSHans Petter Selasky }
321d6b92ffaSHans Petter Selasky
322d6b92ffaSHans Petter Selasky if (!mr->context->ops.rereg_mr) {
323d6b92ffaSHans Petter Selasky errno = ENOSYS;
324d6b92ffaSHans Petter Selasky return IBV_REREG_MR_ERR_INPUT;
325d6b92ffaSHans Petter Selasky }
326d6b92ffaSHans Petter Selasky
327d6b92ffaSHans Petter Selasky if (flags & IBV_REREG_MR_CHANGE_TRANSLATION) {
328d6b92ffaSHans Petter Selasky err = ibv_dontfork_range(addr, length);
329d6b92ffaSHans Petter Selasky if (err)
330d6b92ffaSHans Petter Selasky return IBV_REREG_MR_ERR_DONT_FORK_NEW;
331d6b92ffaSHans Petter Selasky dofork_onfail = 1;
332d6b92ffaSHans Petter Selasky }
333d6b92ffaSHans Petter Selasky
334d6b92ffaSHans Petter Selasky old_addr = mr->addr;
335d6b92ffaSHans Petter Selasky old_len = mr->length;
336d6b92ffaSHans Petter Selasky err = mr->context->ops.rereg_mr(mr, flags, pd, addr, length, access);
337d6b92ffaSHans Petter Selasky if (!err) {
338d6b92ffaSHans Petter Selasky if (flags & IBV_REREG_MR_CHANGE_PD)
339d6b92ffaSHans Petter Selasky mr->pd = pd;
340d6b92ffaSHans Petter Selasky if (flags & IBV_REREG_MR_CHANGE_TRANSLATION) {
341d6b92ffaSHans Petter Selasky mr->addr = addr;
342d6b92ffaSHans Petter Selasky mr->length = length;
343d6b92ffaSHans Petter Selasky err = ibv_dofork_range(old_addr, old_len);
344d6b92ffaSHans Petter Selasky if (err)
345d6b92ffaSHans Petter Selasky return IBV_REREG_MR_ERR_DO_FORK_OLD;
346d6b92ffaSHans Petter Selasky }
347d6b92ffaSHans Petter Selasky } else {
348d6b92ffaSHans Petter Selasky err = IBV_REREG_MR_ERR_CMD;
349d6b92ffaSHans Petter Selasky if (dofork_onfail) {
350d6b92ffaSHans Petter Selasky if (ibv_dofork_range(addr, length))
351d6b92ffaSHans Petter Selasky err = IBV_REREG_MR_ERR_CMD_AND_DO_FORK_NEW;
352d6b92ffaSHans Petter Selasky }
353d6b92ffaSHans Petter Selasky }
354d6b92ffaSHans Petter Selasky
355d6b92ffaSHans Petter Selasky return err;
356d6b92ffaSHans Petter Selasky }
357d6b92ffaSHans Petter Selasky default_symver(__ibv_rereg_mr, ibv_rereg_mr);
358d6b92ffaSHans Petter Selasky
__ibv_dereg_mr(struct ibv_mr * mr)359d6b92ffaSHans Petter Selasky int __ibv_dereg_mr(struct ibv_mr *mr)
360d6b92ffaSHans Petter Selasky {
361d6b92ffaSHans Petter Selasky int ret;
362d6b92ffaSHans Petter Selasky void *addr = mr->addr;
363d6b92ffaSHans Petter Selasky size_t length = mr->length;
364d6b92ffaSHans Petter Selasky
365d6b92ffaSHans Petter Selasky ret = mr->context->ops.dereg_mr(mr);
366d6b92ffaSHans Petter Selasky if (!ret)
367d6b92ffaSHans Petter Selasky ibv_dofork_range(addr, length);
368d6b92ffaSHans Petter Selasky
369d6b92ffaSHans Petter Selasky return ret;
370d6b92ffaSHans Petter Selasky }
371d6b92ffaSHans Petter Selasky default_symver(__ibv_dereg_mr, ibv_dereg_mr);
372d6b92ffaSHans Petter Selasky
ibv_create_comp_channel_v2(struct ibv_context * context)373d6b92ffaSHans Petter Selasky static struct ibv_comp_channel *ibv_create_comp_channel_v2(struct ibv_context *context)
374d6b92ffaSHans Petter Selasky {
375d6b92ffaSHans Petter Selasky struct ibv_abi_compat_v2 *t = context->abi_compat;
376d6b92ffaSHans Petter Selasky static int warned;
377d6b92ffaSHans Petter Selasky
378d6b92ffaSHans Petter Selasky if (!pthread_mutex_trylock(&t->in_use))
379d6b92ffaSHans Petter Selasky return &t->channel;
380d6b92ffaSHans Petter Selasky
381d6b92ffaSHans Petter Selasky if (!warned) {
382d6b92ffaSHans Petter Selasky fprintf(stderr, PFX "Warning: kernel's ABI version %d limits capacity.\n"
383d6b92ffaSHans Petter Selasky " Only one completion channel can be created per context.\n",
384d6b92ffaSHans Petter Selasky abi_ver);
385d6b92ffaSHans Petter Selasky ++warned;
386d6b92ffaSHans Petter Selasky }
387d6b92ffaSHans Petter Selasky
388d6b92ffaSHans Petter Selasky return NULL;
389d6b92ffaSHans Petter Selasky }
390d6b92ffaSHans Petter Selasky
ibv_create_comp_channel(struct ibv_context * context)391d6b92ffaSHans Petter Selasky struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context)
392d6b92ffaSHans Petter Selasky {
393d6b92ffaSHans Petter Selasky struct ibv_comp_channel *channel;
394d6b92ffaSHans Petter Selasky struct ibv_create_comp_channel cmd;
395d6b92ffaSHans Petter Selasky struct ibv_create_comp_channel_resp resp;
396d6b92ffaSHans Petter Selasky
397d6b92ffaSHans Petter Selasky if (abi_ver <= 2)
398d6b92ffaSHans Petter Selasky return ibv_create_comp_channel_v2(context);
399d6b92ffaSHans Petter Selasky
400d6b92ffaSHans Petter Selasky channel = malloc(sizeof *channel);
401d6b92ffaSHans Petter Selasky if (!channel)
402d6b92ffaSHans Petter Selasky return NULL;
403d6b92ffaSHans Petter Selasky
404d6b92ffaSHans Petter Selasky IBV_INIT_CMD_RESP(&cmd, sizeof cmd, CREATE_COMP_CHANNEL, &resp, sizeof resp);
405d6b92ffaSHans Petter Selasky if (write(context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) {
406d6b92ffaSHans Petter Selasky free(channel);
407d6b92ffaSHans Petter Selasky return NULL;
408d6b92ffaSHans Petter Selasky }
409d6b92ffaSHans Petter Selasky
410d6b92ffaSHans Petter Selasky (void) VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
411d6b92ffaSHans Petter Selasky
412d6b92ffaSHans Petter Selasky channel->context = context;
413d6b92ffaSHans Petter Selasky channel->fd = resp.fd;
414d6b92ffaSHans Petter Selasky channel->refcnt = 0;
415d6b92ffaSHans Petter Selasky
416d6b92ffaSHans Petter Selasky return channel;
417d6b92ffaSHans Petter Selasky }
418d6b92ffaSHans Petter Selasky
ibv_destroy_comp_channel_v2(struct ibv_comp_channel * channel)419d6b92ffaSHans Petter Selasky static int ibv_destroy_comp_channel_v2(struct ibv_comp_channel *channel)
420d6b92ffaSHans Petter Selasky {
421d6b92ffaSHans Petter Selasky struct ibv_abi_compat_v2 *t = (struct ibv_abi_compat_v2 *) channel;
422d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&t->in_use);
423d6b92ffaSHans Petter Selasky return 0;
424d6b92ffaSHans Petter Selasky }
425d6b92ffaSHans Petter Selasky
ibv_destroy_comp_channel(struct ibv_comp_channel * channel)426d6b92ffaSHans Petter Selasky int ibv_destroy_comp_channel(struct ibv_comp_channel *channel)
427d6b92ffaSHans Petter Selasky {
428d6b92ffaSHans Petter Selasky struct ibv_context *context;
429d6b92ffaSHans Petter Selasky int ret;
430d6b92ffaSHans Petter Selasky
431d6b92ffaSHans Petter Selasky context = channel->context;
432d6b92ffaSHans Petter Selasky pthread_mutex_lock(&context->mutex);
433d6b92ffaSHans Petter Selasky
434d6b92ffaSHans Petter Selasky if (channel->refcnt) {
435d6b92ffaSHans Petter Selasky ret = EBUSY;
436d6b92ffaSHans Petter Selasky goto out;
437d6b92ffaSHans Petter Selasky }
438d6b92ffaSHans Petter Selasky
439d6b92ffaSHans Petter Selasky if (abi_ver <= 2) {
440d6b92ffaSHans Petter Selasky ret = ibv_destroy_comp_channel_v2(channel);
441d6b92ffaSHans Petter Selasky goto out;
442d6b92ffaSHans Petter Selasky }
443d6b92ffaSHans Petter Selasky
444d6b92ffaSHans Petter Selasky close(channel->fd);
445d6b92ffaSHans Petter Selasky free(channel);
446d6b92ffaSHans Petter Selasky ret = 0;
447d6b92ffaSHans Petter Selasky
448d6b92ffaSHans Petter Selasky out:
449d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&context->mutex);
450d6b92ffaSHans Petter Selasky
451d6b92ffaSHans Petter Selasky return ret;
452d6b92ffaSHans Petter Selasky }
453d6b92ffaSHans Petter Selasky
__ibv_create_cq(struct ibv_context * context,int cqe,void * cq_context,struct ibv_comp_channel * channel,int comp_vector)454d6b92ffaSHans Petter Selasky struct ibv_cq *__ibv_create_cq(struct ibv_context *context, int cqe, void *cq_context,
455d6b92ffaSHans Petter Selasky struct ibv_comp_channel *channel, int comp_vector)
456d6b92ffaSHans Petter Selasky {
457d6b92ffaSHans Petter Selasky struct ibv_cq *cq;
458*a687910fSSean Lim int err = 0;
459d6b92ffaSHans Petter Selasky
460d6b92ffaSHans Petter Selasky cq = context->ops.create_cq(context, cqe, channel, comp_vector);
461d6b92ffaSHans Petter Selasky
462*a687910fSSean Lim if (!cq)
463*a687910fSSean Lim return NULL;
464*a687910fSSean Lim
465*a687910fSSean Lim err = verbs_init_cq(cq, context, channel, cq_context);
466*a687910fSSean Lim if (err)
467*a687910fSSean Lim goto err;
468d6b92ffaSHans Petter Selasky
469d6b92ffaSHans Petter Selasky return cq;
470*a687910fSSean Lim
471*a687910fSSean Lim err:
472*a687910fSSean Lim context->ops.destroy_cq(cq);
473*a687910fSSean Lim
474*a687910fSSean Lim return NULL;
475d6b92ffaSHans Petter Selasky }
476d6b92ffaSHans Petter Selasky default_symver(__ibv_create_cq, ibv_create_cq);
477d6b92ffaSHans Petter Selasky
__ibv_resize_cq(struct ibv_cq * cq,int cqe)478d6b92ffaSHans Petter Selasky int __ibv_resize_cq(struct ibv_cq *cq, int cqe)
479d6b92ffaSHans Petter Selasky {
480d6b92ffaSHans Petter Selasky if (!cq->context->ops.resize_cq)
481d6b92ffaSHans Petter Selasky return ENOSYS;
482d6b92ffaSHans Petter Selasky
483d6b92ffaSHans Petter Selasky return cq->context->ops.resize_cq(cq, cqe);
484d6b92ffaSHans Petter Selasky }
485d6b92ffaSHans Petter Selasky default_symver(__ibv_resize_cq, ibv_resize_cq);
486d6b92ffaSHans Petter Selasky
__ibv_destroy_cq(struct ibv_cq * cq)487d6b92ffaSHans Petter Selasky int __ibv_destroy_cq(struct ibv_cq *cq)
488d6b92ffaSHans Petter Selasky {
489d6b92ffaSHans Petter Selasky struct ibv_comp_channel *channel = cq->channel;
490d6b92ffaSHans Petter Selasky int ret;
491d6b92ffaSHans Petter Selasky
492d6b92ffaSHans Petter Selasky ret = cq->context->ops.destroy_cq(cq);
493d6b92ffaSHans Petter Selasky
494d6b92ffaSHans Petter Selasky if (channel) {
495d6b92ffaSHans Petter Selasky if (!ret) {
496d6b92ffaSHans Petter Selasky pthread_mutex_lock(&channel->context->mutex);
497d6b92ffaSHans Petter Selasky --channel->refcnt;
498d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&channel->context->mutex);
499d6b92ffaSHans Petter Selasky }
500d6b92ffaSHans Petter Selasky }
501d6b92ffaSHans Petter Selasky
502d6b92ffaSHans Petter Selasky return ret;
503d6b92ffaSHans Petter Selasky }
504d6b92ffaSHans Petter Selasky default_symver(__ibv_destroy_cq, ibv_destroy_cq);
505d6b92ffaSHans Petter Selasky
__ibv_get_cq_event(struct ibv_comp_channel * channel,struct ibv_cq ** cq,void ** cq_context)506d6b92ffaSHans Petter Selasky int __ibv_get_cq_event(struct ibv_comp_channel *channel,
507d6b92ffaSHans Petter Selasky struct ibv_cq **cq, void **cq_context)
508d6b92ffaSHans Petter Selasky {
509d6b92ffaSHans Petter Selasky struct ibv_comp_event ev;
510d6b92ffaSHans Petter Selasky
511d6b92ffaSHans Petter Selasky if (read(channel->fd, &ev, sizeof ev) != sizeof ev)
512d6b92ffaSHans Petter Selasky return -1;
513d6b92ffaSHans Petter Selasky
514d6b92ffaSHans Petter Selasky *cq = (struct ibv_cq *) (uintptr_t) ev.cq_handle;
515d6b92ffaSHans Petter Selasky *cq_context = (*cq)->cq_context;
516d6b92ffaSHans Petter Selasky
517d6b92ffaSHans Petter Selasky if ((*cq)->context->ops.cq_event)
518d6b92ffaSHans Petter Selasky (*cq)->context->ops.cq_event(*cq);
519d6b92ffaSHans Petter Selasky
520d6b92ffaSHans Petter Selasky return 0;
521d6b92ffaSHans Petter Selasky }
522d6b92ffaSHans Petter Selasky default_symver(__ibv_get_cq_event, ibv_get_cq_event);
523d6b92ffaSHans Petter Selasky
__ibv_ack_cq_events(struct ibv_cq * cq,unsigned int nevents)524d6b92ffaSHans Petter Selasky void __ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
525d6b92ffaSHans Petter Selasky {
526d6b92ffaSHans Petter Selasky pthread_mutex_lock(&cq->mutex);
527d6b92ffaSHans Petter Selasky cq->comp_events_completed += nevents;
528d6b92ffaSHans Petter Selasky pthread_cond_signal(&cq->cond);
529d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&cq->mutex);
530d6b92ffaSHans Petter Selasky }
531d6b92ffaSHans Petter Selasky default_symver(__ibv_ack_cq_events, ibv_ack_cq_events);
532d6b92ffaSHans Petter Selasky
__ibv_create_srq(struct ibv_pd * pd,struct ibv_srq_init_attr * srq_init_attr)533d6b92ffaSHans Petter Selasky struct ibv_srq *__ibv_create_srq(struct ibv_pd *pd,
534d6b92ffaSHans Petter Selasky struct ibv_srq_init_attr *srq_init_attr)
535d6b92ffaSHans Petter Selasky {
536d6b92ffaSHans Petter Selasky struct ibv_srq *srq;
537d6b92ffaSHans Petter Selasky
538d6b92ffaSHans Petter Selasky if (!pd->context->ops.create_srq)
539d6b92ffaSHans Petter Selasky return NULL;
540d6b92ffaSHans Petter Selasky
541d6b92ffaSHans Petter Selasky srq = pd->context->ops.create_srq(pd, srq_init_attr);
542*a687910fSSean Lim if (!srq)
543*a687910fSSean Lim return NULL;
544*a687910fSSean Lim
545d6b92ffaSHans Petter Selasky srq->context = pd->context;
546d6b92ffaSHans Petter Selasky srq->srq_context = srq_init_attr->srq_context;
547d6b92ffaSHans Petter Selasky srq->pd = pd;
548d6b92ffaSHans Petter Selasky srq->events_completed = 0;
549*a687910fSSean Lim if (pthread_mutex_init(&srq->mutex, NULL))
550*a687910fSSean Lim goto err;
551*a687910fSSean Lim if (pthread_cond_init(&srq->cond, NULL))
552*a687910fSSean Lim goto err_mutex;
553d6b92ffaSHans Petter Selasky
554d6b92ffaSHans Petter Selasky return srq;
555*a687910fSSean Lim
556*a687910fSSean Lim err_mutex:
557*a687910fSSean Lim pthread_mutex_destroy(&srq->mutex);
558*a687910fSSean Lim err:
559*a687910fSSean Lim pd->context->ops.destroy_srq(srq);
560*a687910fSSean Lim
561*a687910fSSean Lim return NULL;
562d6b92ffaSHans Petter Selasky }
563d6b92ffaSHans Petter Selasky default_symver(__ibv_create_srq, ibv_create_srq);
564d6b92ffaSHans Petter Selasky
__ibv_modify_srq(struct ibv_srq * srq,struct ibv_srq_attr * srq_attr,int srq_attr_mask)565d6b92ffaSHans Petter Selasky int __ibv_modify_srq(struct ibv_srq *srq,
566d6b92ffaSHans Petter Selasky struct ibv_srq_attr *srq_attr,
567d6b92ffaSHans Petter Selasky int srq_attr_mask)
568d6b92ffaSHans Petter Selasky {
569d6b92ffaSHans Petter Selasky return srq->context->ops.modify_srq(srq, srq_attr, srq_attr_mask);
570d6b92ffaSHans Petter Selasky }
571d6b92ffaSHans Petter Selasky default_symver(__ibv_modify_srq, ibv_modify_srq);
572d6b92ffaSHans Petter Selasky
__ibv_query_srq(struct ibv_srq * srq,struct ibv_srq_attr * srq_attr)573d6b92ffaSHans Petter Selasky int __ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr)
574d6b92ffaSHans Petter Selasky {
575d6b92ffaSHans Petter Selasky return srq->context->ops.query_srq(srq, srq_attr);
576d6b92ffaSHans Petter Selasky }
577d6b92ffaSHans Petter Selasky default_symver(__ibv_query_srq, ibv_query_srq);
578d6b92ffaSHans Petter Selasky
__ibv_destroy_srq(struct ibv_srq * srq)579d6b92ffaSHans Petter Selasky int __ibv_destroy_srq(struct ibv_srq *srq)
580d6b92ffaSHans Petter Selasky {
581*a687910fSSean Lim pthread_cond_destroy(&srq->cond);
582*a687910fSSean Lim pthread_mutex_destroy(&srq->mutex);
583d6b92ffaSHans Petter Selasky return srq->context->ops.destroy_srq(srq);
584d6b92ffaSHans Petter Selasky }
585d6b92ffaSHans Petter Selasky default_symver(__ibv_destroy_srq, ibv_destroy_srq);
586d6b92ffaSHans Petter Selasky
__ibv_create_qp(struct ibv_pd * pd,struct ibv_qp_init_attr * qp_init_attr)587d6b92ffaSHans Petter Selasky struct ibv_qp *__ibv_create_qp(struct ibv_pd *pd,
588d6b92ffaSHans Petter Selasky struct ibv_qp_init_attr *qp_init_attr)
589d6b92ffaSHans Petter Selasky {
590d6b92ffaSHans Petter Selasky struct ibv_qp *qp = pd->context->ops.create_qp(pd, qp_init_attr);
591d6b92ffaSHans Petter Selasky
592d6b92ffaSHans Petter Selasky if (qp) {
593d6b92ffaSHans Petter Selasky qp->context = pd->context;
594d6b92ffaSHans Petter Selasky qp->qp_context = qp_init_attr->qp_context;
595d6b92ffaSHans Petter Selasky qp->pd = pd;
596d6b92ffaSHans Petter Selasky qp->send_cq = qp_init_attr->send_cq;
597d6b92ffaSHans Petter Selasky qp->recv_cq = qp_init_attr->recv_cq;
598d6b92ffaSHans Petter Selasky qp->srq = qp_init_attr->srq;
599d6b92ffaSHans Petter Selasky qp->qp_type = qp_init_attr->qp_type;
600d6b92ffaSHans Petter Selasky qp->state = IBV_QPS_RESET;
601d6b92ffaSHans Petter Selasky qp->events_completed = 0;
602d6b92ffaSHans Petter Selasky pthread_mutex_init(&qp->mutex, NULL);
603d6b92ffaSHans Petter Selasky pthread_cond_init(&qp->cond, NULL);
604d6b92ffaSHans Petter Selasky }
605d6b92ffaSHans Petter Selasky
606d6b92ffaSHans Petter Selasky return qp;
607d6b92ffaSHans Petter Selasky }
608d6b92ffaSHans Petter Selasky default_symver(__ibv_create_qp, ibv_create_qp);
609d6b92ffaSHans Petter Selasky
__ibv_query_qp(struct ibv_qp * qp,struct ibv_qp_attr * attr,int attr_mask,struct ibv_qp_init_attr * init_attr)610d6b92ffaSHans Petter Selasky int __ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
611d6b92ffaSHans Petter Selasky int attr_mask,
612d6b92ffaSHans Petter Selasky struct ibv_qp_init_attr *init_attr)
613d6b92ffaSHans Petter Selasky {
614d6b92ffaSHans Petter Selasky int ret;
615d6b92ffaSHans Petter Selasky
616d6b92ffaSHans Petter Selasky ret = qp->context->ops.query_qp(qp, attr, attr_mask, init_attr);
617d6b92ffaSHans Petter Selasky if (ret)
618d6b92ffaSHans Petter Selasky return ret;
619d6b92ffaSHans Petter Selasky
620d6b92ffaSHans Petter Selasky if (attr_mask & IBV_QP_STATE)
621d6b92ffaSHans Petter Selasky qp->state = attr->qp_state;
622d6b92ffaSHans Petter Selasky
623d6b92ffaSHans Petter Selasky return 0;
624d6b92ffaSHans Petter Selasky }
625d6b92ffaSHans Petter Selasky default_symver(__ibv_query_qp, ibv_query_qp);
626d6b92ffaSHans Petter Selasky
__ibv_modify_qp(struct ibv_qp * qp,struct ibv_qp_attr * attr,int attr_mask)627d6b92ffaSHans Petter Selasky int __ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
628d6b92ffaSHans Petter Selasky int attr_mask)
629d6b92ffaSHans Petter Selasky {
630d6b92ffaSHans Petter Selasky int ret;
631d6b92ffaSHans Petter Selasky
632d6b92ffaSHans Petter Selasky ret = qp->context->ops.modify_qp(qp, attr, attr_mask);
633d6b92ffaSHans Petter Selasky if (ret)
634d6b92ffaSHans Petter Selasky return ret;
635d6b92ffaSHans Petter Selasky
636d6b92ffaSHans Petter Selasky if (attr_mask & IBV_QP_STATE)
637d6b92ffaSHans Petter Selasky qp->state = attr->qp_state;
638d6b92ffaSHans Petter Selasky
639d6b92ffaSHans Petter Selasky return 0;
640d6b92ffaSHans Petter Selasky }
641d6b92ffaSHans Petter Selasky default_symver(__ibv_modify_qp, ibv_modify_qp);
642d6b92ffaSHans Petter Selasky
__ibv_destroy_qp(struct ibv_qp * qp)643d6b92ffaSHans Petter Selasky int __ibv_destroy_qp(struct ibv_qp *qp)
644d6b92ffaSHans Petter Selasky {
645d6b92ffaSHans Petter Selasky return qp->context->ops.destroy_qp(qp);
646d6b92ffaSHans Petter Selasky }
647d6b92ffaSHans Petter Selasky default_symver(__ibv_destroy_qp, ibv_destroy_qp);
648d6b92ffaSHans Petter Selasky
__ibv_create_ah(struct ibv_pd * pd,struct ibv_ah_attr * attr)649d6b92ffaSHans Petter Selasky struct ibv_ah *__ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr)
650d6b92ffaSHans Petter Selasky {
651d6b92ffaSHans Petter Selasky struct ibv_ah *ah = pd->context->ops.create_ah(pd, attr);
652d6b92ffaSHans Petter Selasky
653d6b92ffaSHans Petter Selasky if (ah) {
654d6b92ffaSHans Petter Selasky ah->context = pd->context;
655d6b92ffaSHans Petter Selasky ah->pd = pd;
656d6b92ffaSHans Petter Selasky }
657d6b92ffaSHans Petter Selasky
658d6b92ffaSHans Petter Selasky return ah;
659d6b92ffaSHans Petter Selasky }
660d6b92ffaSHans Petter Selasky default_symver(__ibv_create_ah, ibv_create_ah);
661d6b92ffaSHans Petter Selasky
662d6b92ffaSHans Petter Selasky /* GID types as appear in sysfs, no change is expected as of ABI
663d6b92ffaSHans Petter Selasky * compatibility.
664d6b92ffaSHans Petter Selasky */
665d6b92ffaSHans Petter Selasky #define V1_TYPE "IB/RoCE v1"
666d6b92ffaSHans Petter Selasky #define V2_TYPE "RoCE v2"
ibv_query_gid_type(struct ibv_context * context,uint8_t port_num,unsigned int index,enum ibv_gid_type * type)667d6b92ffaSHans Petter Selasky int ibv_query_gid_type(struct ibv_context *context, uint8_t port_num,
668d6b92ffaSHans Petter Selasky unsigned int index, enum ibv_gid_type *type)
669d6b92ffaSHans Petter Selasky {
670d6b92ffaSHans Petter Selasky char name[32];
671d6b92ffaSHans Petter Selasky char buff[11];
672d6b92ffaSHans Petter Selasky
673d6b92ffaSHans Petter Selasky snprintf(name, sizeof(name), "ports/%d/gid_attrs/types/%d", port_num,
674d6b92ffaSHans Petter Selasky index);
675d6b92ffaSHans Petter Selasky
676d6b92ffaSHans Petter Selasky /* Reset errno so that we can rely on its value upon any error flow in
677d6b92ffaSHans Petter Selasky * ibv_read_sysfs_file.
678d6b92ffaSHans Petter Selasky */
679d6b92ffaSHans Petter Selasky errno = 0;
680d6b92ffaSHans Petter Selasky if (ibv_read_sysfs_file(context->device->ibdev_path, name, buff,
681d6b92ffaSHans Petter Selasky sizeof(buff)) <= 0) {
682d6b92ffaSHans Petter Selasky char *dir_path;
683d6b92ffaSHans Petter Selasky DIR *dir;
684d6b92ffaSHans Petter Selasky
685d6b92ffaSHans Petter Selasky if (errno == EINVAL) {
686d6b92ffaSHans Petter Selasky /* In IB, this file doesn't exist and the kernel sets
687d6b92ffaSHans Petter Selasky * errno to -EINVAL.
688d6b92ffaSHans Petter Selasky */
689d6b92ffaSHans Petter Selasky *type = IBV_GID_TYPE_IB_ROCE_V1;
690d6b92ffaSHans Petter Selasky return 0;
691d6b92ffaSHans Petter Selasky }
692d6b92ffaSHans Petter Selasky if (asprintf(&dir_path, "%s/%s/%d/%s/",
693d6b92ffaSHans Petter Selasky context->device->ibdev_path, "ports", port_num,
694d6b92ffaSHans Petter Selasky "gid_attrs") < 0)
695d6b92ffaSHans Petter Selasky return -1;
696d6b92ffaSHans Petter Selasky dir = opendir(dir_path);
697d6b92ffaSHans Petter Selasky free(dir_path);
698d6b92ffaSHans Petter Selasky if (!dir) {
699d6b92ffaSHans Petter Selasky if (errno == ENOENT)
700d6b92ffaSHans Petter Selasky /* Assuming that if gid_attrs doesn't exist,
701d6b92ffaSHans Petter Selasky * we have an old kernel and all GIDs are
702d6b92ffaSHans Petter Selasky * IB/RoCE v1
703d6b92ffaSHans Petter Selasky */
704d6b92ffaSHans Petter Selasky *type = IBV_GID_TYPE_IB_ROCE_V1;
705d6b92ffaSHans Petter Selasky else
706d6b92ffaSHans Petter Selasky return -1;
707d6b92ffaSHans Petter Selasky } else {
708d6b92ffaSHans Petter Selasky closedir(dir);
709d6b92ffaSHans Petter Selasky errno = EFAULT;
710d6b92ffaSHans Petter Selasky return -1;
711d6b92ffaSHans Petter Selasky }
712d6b92ffaSHans Petter Selasky } else {
713d6b92ffaSHans Petter Selasky if (!strcmp(buff, V1_TYPE)) {
714d6b92ffaSHans Petter Selasky *type = IBV_GID_TYPE_IB_ROCE_V1;
715d6b92ffaSHans Petter Selasky } else if (!strcmp(buff, V2_TYPE)) {
716d6b92ffaSHans Petter Selasky *type = IBV_GID_TYPE_ROCE_V2;
717d6b92ffaSHans Petter Selasky } else {
718d6b92ffaSHans Petter Selasky errno = ENOTSUP;
719d6b92ffaSHans Petter Selasky return -1;
720d6b92ffaSHans Petter Selasky }
721d6b92ffaSHans Petter Selasky }
722d6b92ffaSHans Petter Selasky
723d6b92ffaSHans Petter Selasky return 0;
724d6b92ffaSHans Petter Selasky }
725d6b92ffaSHans Petter Selasky
ibv_find_gid_index(struct ibv_context * context,uint8_t port_num,union ibv_gid * gid,enum ibv_gid_type gid_type)726d6b92ffaSHans Petter Selasky static int ibv_find_gid_index(struct ibv_context *context, uint8_t port_num,
727d6b92ffaSHans Petter Selasky union ibv_gid *gid, enum ibv_gid_type gid_type)
728d6b92ffaSHans Petter Selasky {
729d6b92ffaSHans Petter Selasky enum ibv_gid_type sgid_type = 0;
730d6b92ffaSHans Petter Selasky union ibv_gid sgid;
731d6b92ffaSHans Petter Selasky int i = 0, ret;
732d6b92ffaSHans Petter Selasky
733d6b92ffaSHans Petter Selasky do {
734d6b92ffaSHans Petter Selasky ret = ibv_query_gid(context, port_num, i, &sgid);
735d6b92ffaSHans Petter Selasky if (!ret) {
736d6b92ffaSHans Petter Selasky ret = ibv_query_gid_type(context, port_num, i,
737d6b92ffaSHans Petter Selasky &sgid_type);
738d6b92ffaSHans Petter Selasky }
739d6b92ffaSHans Petter Selasky i++;
740d6b92ffaSHans Petter Selasky } while (!ret && (memcmp(&sgid, gid, sizeof(*gid)) ||
741d6b92ffaSHans Petter Selasky (gid_type != sgid_type)));
742d6b92ffaSHans Petter Selasky
743d6b92ffaSHans Petter Selasky return ret ? ret : i - 1;
744d6b92ffaSHans Petter Selasky }
745d6b92ffaSHans Petter Selasky
map_ipv4_addr_to_ipv6(__be32 ipv4,struct in6_addr * ipv6)746d6b92ffaSHans Petter Selasky static inline void map_ipv4_addr_to_ipv6(__be32 ipv4, struct in6_addr *ipv6)
747d6b92ffaSHans Petter Selasky {
748d6b92ffaSHans Petter Selasky ipv6->s6_addr32[0] = 0;
749d6b92ffaSHans Petter Selasky ipv6->s6_addr32[1] = 0;
750d6b92ffaSHans Petter Selasky ipv6->s6_addr32[2] = htobe32(0x0000FFFF);
751d6b92ffaSHans Petter Selasky ipv6->s6_addr32[3] = ipv4;
752d6b92ffaSHans Petter Selasky }
753d6b92ffaSHans Petter Selasky
ipv4_calc_hdr_csum(uint16_t * data,unsigned int num_hwords)754d6b92ffaSHans Petter Selasky static inline __sum16 ipv4_calc_hdr_csum(uint16_t *data, unsigned int num_hwords)
755d6b92ffaSHans Petter Selasky {
756d6b92ffaSHans Petter Selasky unsigned int i = 0;
757d6b92ffaSHans Petter Selasky uint32_t sum = 0;
758d6b92ffaSHans Petter Selasky
759d6b92ffaSHans Petter Selasky for (i = 0; i < num_hwords; i++)
760d6b92ffaSHans Petter Selasky sum += *(data++);
761d6b92ffaSHans Petter Selasky
762d6b92ffaSHans Petter Selasky sum = (sum & 0xffff) + (sum >> 16);
763d6b92ffaSHans Petter Selasky
764d6b92ffaSHans Petter Selasky return (__sum16)~sum;
765d6b92ffaSHans Petter Selasky }
766d6b92ffaSHans Petter Selasky
get_grh_header_version(struct ibv_grh * grh)767d6b92ffaSHans Petter Selasky static inline int get_grh_header_version(struct ibv_grh *grh)
768d6b92ffaSHans Petter Selasky {
769d6b92ffaSHans Petter Selasky int ip6h_version = (be32toh(grh->version_tclass_flow) >> 28) & 0xf;
770d6b92ffaSHans Petter Selasky struct ip *ip4h = (struct ip *)((void *)grh + 20);
771d6b92ffaSHans Petter Selasky struct ip ip4h_checked;
772d6b92ffaSHans Petter Selasky
773d6b92ffaSHans Petter Selasky if (ip6h_version != 6) {
774d6b92ffaSHans Petter Selasky if (ip4h->ip_v == 4)
775d6b92ffaSHans Petter Selasky return 4;
776d6b92ffaSHans Petter Selasky errno = EPROTONOSUPPORT;
777d6b92ffaSHans Petter Selasky return -1;
778d6b92ffaSHans Petter Selasky }
779d6b92ffaSHans Petter Selasky /* version may be 6 or 4 */
780d6b92ffaSHans Petter Selasky if (ip4h->ip_hl != 5) /* IPv4 header length must be 5 for RoCE v2. */
781d6b92ffaSHans Petter Selasky return 6;
782d6b92ffaSHans Petter Selasky /*
783d6b92ffaSHans Petter Selasky * Verify checksum.
784d6b92ffaSHans Petter Selasky * We can't write on scattered buffers so we have to copy to temp
785d6b92ffaSHans Petter Selasky * buffer.
786d6b92ffaSHans Petter Selasky */
787d6b92ffaSHans Petter Selasky memcpy(&ip4h_checked, ip4h, sizeof(ip4h_checked));
788d6b92ffaSHans Petter Selasky /* Need to set the checksum field (check) to 0 before re-calculating
789d6b92ffaSHans Petter Selasky * the checksum.
790d6b92ffaSHans Petter Selasky */
791d6b92ffaSHans Petter Selasky ip4h_checked.ip_sum = 0;
792d6b92ffaSHans Petter Selasky ip4h_checked.ip_sum = ipv4_calc_hdr_csum((uint16_t *)&ip4h_checked, 10);
793d6b92ffaSHans Petter Selasky /* if IPv4 header checksum is OK, believe it */
794d6b92ffaSHans Petter Selasky if (ip4h->ip_sum == ip4h_checked.ip_sum)
795d6b92ffaSHans Petter Selasky return 4;
796d6b92ffaSHans Petter Selasky return 6;
797d6b92ffaSHans Petter Selasky }
798d6b92ffaSHans Petter Selasky
set_ah_attr_generic_fields(struct ibv_ah_attr * ah_attr,struct ibv_wc * wc,struct ibv_grh * grh,uint8_t port_num)799d6b92ffaSHans Petter Selasky static inline void set_ah_attr_generic_fields(struct ibv_ah_attr *ah_attr,
800d6b92ffaSHans Petter Selasky struct ibv_wc *wc,
801d6b92ffaSHans Petter Selasky struct ibv_grh *grh,
802d6b92ffaSHans Petter Selasky uint8_t port_num)
803d6b92ffaSHans Petter Selasky {
804d6b92ffaSHans Petter Selasky uint32_t flow_class;
805d6b92ffaSHans Petter Selasky
806d6b92ffaSHans Petter Selasky flow_class = be32toh(grh->version_tclass_flow);
807d6b92ffaSHans Petter Selasky ah_attr->grh.flow_label = flow_class & 0xFFFFF;
808d6b92ffaSHans Petter Selasky ah_attr->dlid = wc->slid;
809d6b92ffaSHans Petter Selasky ah_attr->sl = wc->sl;
810d6b92ffaSHans Petter Selasky ah_attr->src_path_bits = wc->dlid_path_bits;
811d6b92ffaSHans Petter Selasky ah_attr->port_num = port_num;
812d6b92ffaSHans Petter Selasky }
813d6b92ffaSHans Petter Selasky
set_ah_attr_by_ipv4(struct ibv_context * context,struct ibv_ah_attr * ah_attr,struct ip * ip4h,uint8_t port_num)814d6b92ffaSHans Petter Selasky static inline int set_ah_attr_by_ipv4(struct ibv_context *context,
815d6b92ffaSHans Petter Selasky struct ibv_ah_attr *ah_attr,
816d6b92ffaSHans Petter Selasky struct ip *ip4h, uint8_t port_num)
817d6b92ffaSHans Petter Selasky {
818d6b92ffaSHans Petter Selasky union ibv_gid sgid;
819d6b92ffaSHans Petter Selasky int ret;
820d6b92ffaSHans Petter Selasky
821d6b92ffaSHans Petter Selasky /* No point searching multicast GIDs in GID table */
822d6b92ffaSHans Petter Selasky if (IN_CLASSD(be32toh(ip4h->ip_dst.s_addr))) {
823d6b92ffaSHans Petter Selasky errno = EINVAL;
824d6b92ffaSHans Petter Selasky return -1;
825d6b92ffaSHans Petter Selasky }
826d6b92ffaSHans Petter Selasky
827d6b92ffaSHans Petter Selasky map_ipv4_addr_to_ipv6(ip4h->ip_dst.s_addr, (struct in6_addr *)&sgid);
828d6b92ffaSHans Petter Selasky ret = ibv_find_gid_index(context, port_num, &sgid,
829d6b92ffaSHans Petter Selasky IBV_GID_TYPE_ROCE_V2);
830d6b92ffaSHans Petter Selasky if (ret < 0)
831d6b92ffaSHans Petter Selasky return ret;
832d6b92ffaSHans Petter Selasky
833d6b92ffaSHans Petter Selasky map_ipv4_addr_to_ipv6(ip4h->ip_src.s_addr,
834d6b92ffaSHans Petter Selasky (struct in6_addr *)&ah_attr->grh.dgid);
835d6b92ffaSHans Petter Selasky ah_attr->grh.sgid_index = (uint8_t) ret;
836d6b92ffaSHans Petter Selasky ah_attr->grh.hop_limit = ip4h->ip_ttl;
837d6b92ffaSHans Petter Selasky ah_attr->grh.traffic_class = ip4h->ip_tos;
838d6b92ffaSHans Petter Selasky
839d6b92ffaSHans Petter Selasky return 0;
840d6b92ffaSHans Petter Selasky }
841d6b92ffaSHans Petter Selasky
842d6b92ffaSHans Petter Selasky #define IB_NEXT_HDR 0x1b
set_ah_attr_by_ipv6(struct ibv_context * context,struct ibv_ah_attr * ah_attr,struct ibv_grh * grh,uint8_t port_num)843d6b92ffaSHans Petter Selasky static inline int set_ah_attr_by_ipv6(struct ibv_context *context,
844d6b92ffaSHans Petter Selasky struct ibv_ah_attr *ah_attr,
845d6b92ffaSHans Petter Selasky struct ibv_grh *grh, uint8_t port_num)
846d6b92ffaSHans Petter Selasky {
847d6b92ffaSHans Petter Selasky uint32_t flow_class;
848d6b92ffaSHans Petter Selasky uint32_t sgid_type;
849d6b92ffaSHans Petter Selasky int ret;
850d6b92ffaSHans Petter Selasky
851d6b92ffaSHans Petter Selasky /* No point searching multicast GIDs in GID table */
852d6b92ffaSHans Petter Selasky if (grh->dgid.raw[0] == 0xFF) {
853d6b92ffaSHans Petter Selasky errno = EINVAL;
854d6b92ffaSHans Petter Selasky return -1;
855d6b92ffaSHans Petter Selasky }
856d6b92ffaSHans Petter Selasky
857d6b92ffaSHans Petter Selasky ah_attr->grh.dgid = grh->sgid;
858d6b92ffaSHans Petter Selasky if (grh->next_hdr == IPPROTO_UDP) {
859d6b92ffaSHans Petter Selasky sgid_type = IBV_GID_TYPE_ROCE_V2;
860d6b92ffaSHans Petter Selasky } else if (grh->next_hdr == IB_NEXT_HDR) {
861d6b92ffaSHans Petter Selasky sgid_type = IBV_GID_TYPE_IB_ROCE_V1;
862d6b92ffaSHans Petter Selasky } else {
863d6b92ffaSHans Petter Selasky errno = EPROTONOSUPPORT;
864d6b92ffaSHans Petter Selasky return -1;
865d6b92ffaSHans Petter Selasky }
866d6b92ffaSHans Petter Selasky
867d6b92ffaSHans Petter Selasky ret = ibv_find_gid_index(context, port_num, &grh->dgid,
868d6b92ffaSHans Petter Selasky sgid_type);
869d6b92ffaSHans Petter Selasky if (ret < 0)
870d6b92ffaSHans Petter Selasky return ret;
871d6b92ffaSHans Petter Selasky
872d6b92ffaSHans Petter Selasky ah_attr->grh.sgid_index = (uint8_t) ret;
873d6b92ffaSHans Petter Selasky flow_class = be32toh(grh->version_tclass_flow);
874d6b92ffaSHans Petter Selasky ah_attr->grh.hop_limit = grh->hop_limit;
875d6b92ffaSHans Petter Selasky ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
876d6b92ffaSHans Petter Selasky
877d6b92ffaSHans Petter Selasky return 0;
878d6b92ffaSHans Petter Selasky }
879d6b92ffaSHans Petter Selasky
ibv_init_ah_from_wc(struct ibv_context * context,uint8_t port_num,struct ibv_wc * wc,struct ibv_grh * grh,struct ibv_ah_attr * ah_attr)880d6b92ffaSHans Petter Selasky int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num,
881d6b92ffaSHans Petter Selasky struct ibv_wc *wc, struct ibv_grh *grh,
882d6b92ffaSHans Petter Selasky struct ibv_ah_attr *ah_attr)
883d6b92ffaSHans Petter Selasky {
884d6b92ffaSHans Petter Selasky int version;
885d6b92ffaSHans Petter Selasky int ret = 0;
886d6b92ffaSHans Petter Selasky
887d6b92ffaSHans Petter Selasky memset(ah_attr, 0, sizeof *ah_attr);
888d6b92ffaSHans Petter Selasky set_ah_attr_generic_fields(ah_attr, wc, grh, port_num);
889d6b92ffaSHans Petter Selasky
890d6b92ffaSHans Petter Selasky if (wc->wc_flags & IBV_WC_GRH) {
891d6b92ffaSHans Petter Selasky ah_attr->is_global = 1;
892d6b92ffaSHans Petter Selasky version = get_grh_header_version(grh);
893d6b92ffaSHans Petter Selasky
894d6b92ffaSHans Petter Selasky if (version == 4)
895d6b92ffaSHans Petter Selasky ret = set_ah_attr_by_ipv4(context, ah_attr,
896d6b92ffaSHans Petter Selasky (struct ip *)((void *)grh + 20),
897d6b92ffaSHans Petter Selasky port_num);
898d6b92ffaSHans Petter Selasky else if (version == 6)
899d6b92ffaSHans Petter Selasky ret = set_ah_attr_by_ipv6(context, ah_attr, grh,
900d6b92ffaSHans Petter Selasky port_num);
901d6b92ffaSHans Petter Selasky else
902d6b92ffaSHans Petter Selasky ret = -1;
903d6b92ffaSHans Petter Selasky }
904d6b92ffaSHans Petter Selasky
905d6b92ffaSHans Petter Selasky return ret;
906d6b92ffaSHans Petter Selasky }
907d6b92ffaSHans Petter Selasky
ibv_create_ah_from_wc(struct ibv_pd * pd,struct ibv_wc * wc,struct ibv_grh * grh,uint8_t port_num)908d6b92ffaSHans Petter Selasky struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc,
909d6b92ffaSHans Petter Selasky struct ibv_grh *grh, uint8_t port_num)
910d6b92ffaSHans Petter Selasky {
911d6b92ffaSHans Petter Selasky struct ibv_ah_attr ah_attr;
912d6b92ffaSHans Petter Selasky int ret;
913d6b92ffaSHans Petter Selasky
914d6b92ffaSHans Petter Selasky ret = ibv_init_ah_from_wc(pd->context, port_num, wc, grh, &ah_attr);
915d6b92ffaSHans Petter Selasky if (ret)
916d6b92ffaSHans Petter Selasky return NULL;
917d6b92ffaSHans Petter Selasky
918d6b92ffaSHans Petter Selasky return ibv_create_ah(pd, &ah_attr);
919d6b92ffaSHans Petter Selasky }
920d6b92ffaSHans Petter Selasky
__ibv_destroy_ah(struct ibv_ah * ah)921d6b92ffaSHans Petter Selasky int __ibv_destroy_ah(struct ibv_ah *ah)
922d6b92ffaSHans Petter Selasky {
923d6b92ffaSHans Petter Selasky return ah->context->ops.destroy_ah(ah);
924d6b92ffaSHans Petter Selasky }
925d6b92ffaSHans Petter Selasky default_symver(__ibv_destroy_ah, ibv_destroy_ah);
926d6b92ffaSHans Petter Selasky
__ibv_attach_mcast(struct ibv_qp * qp,const union ibv_gid * gid,uint16_t lid)927d6b92ffaSHans Petter Selasky int __ibv_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid)
928d6b92ffaSHans Petter Selasky {
929d6b92ffaSHans Petter Selasky return qp->context->ops.attach_mcast(qp, gid, lid);
930d6b92ffaSHans Petter Selasky }
931d6b92ffaSHans Petter Selasky default_symver(__ibv_attach_mcast, ibv_attach_mcast);
932d6b92ffaSHans Petter Selasky
__ibv_detach_mcast(struct ibv_qp * qp,const union ibv_gid * gid,uint16_t lid)933d6b92ffaSHans Petter Selasky int __ibv_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid)
934d6b92ffaSHans Petter Selasky {
935d6b92ffaSHans Petter Selasky return qp->context->ops.detach_mcast(qp, gid, lid);
936d6b92ffaSHans Petter Selasky }
937d6b92ffaSHans Petter Selasky default_symver(__ibv_detach_mcast, ibv_detach_mcast);
938d6b92ffaSHans Petter Selasky
ipv6_addr_v4mapped(const struct in6_addr * a)939d6b92ffaSHans Petter Selasky static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
940d6b92ffaSHans Petter Selasky {
941d6b92ffaSHans Petter Selasky return IN6_IS_ADDR_V4MAPPED(a) ||
942d6b92ffaSHans Petter Selasky /* IPv4 encoded multicast addresses */
943d6b92ffaSHans Petter Selasky (a->s6_addr32[0] == htobe32(0xff0e0000) &&
944d6b92ffaSHans Petter Selasky ((a->s6_addr32[1] |
945d6b92ffaSHans Petter Selasky (a->s6_addr32[2] ^ htobe32(0x0000ffff))) == 0UL));
946d6b92ffaSHans Petter Selasky }
947d6b92ffaSHans Petter Selasky
948d6b92ffaSHans Petter Selasky struct peer_address {
949d6b92ffaSHans Petter Selasky void *address;
950d6b92ffaSHans Petter Selasky uint32_t size;
951d6b92ffaSHans Petter Selasky };
952d6b92ffaSHans Petter Selasky
create_peer_from_gid(int family,void * raw_gid,struct peer_address * peer_address)953d6b92ffaSHans Petter Selasky static inline int create_peer_from_gid(int family, void *raw_gid,
954d6b92ffaSHans Petter Selasky struct peer_address *peer_address)
955d6b92ffaSHans Petter Selasky {
956d6b92ffaSHans Petter Selasky switch (family) {
957d6b92ffaSHans Petter Selasky case AF_INET:
958d6b92ffaSHans Petter Selasky peer_address->address = raw_gid + 12;
959d6b92ffaSHans Petter Selasky peer_address->size = 4;
960d6b92ffaSHans Petter Selasky break;
961d6b92ffaSHans Petter Selasky case AF_INET6:
962d6b92ffaSHans Petter Selasky peer_address->address = raw_gid;
963d6b92ffaSHans Petter Selasky peer_address->size = 16;
964d6b92ffaSHans Petter Selasky break;
965d6b92ffaSHans Petter Selasky default:
966d6b92ffaSHans Petter Selasky return -1;
967d6b92ffaSHans Petter Selasky }
968d6b92ffaSHans Petter Selasky
969d6b92ffaSHans Petter Selasky return 0;
970d6b92ffaSHans Petter Selasky }
971d6b92ffaSHans Petter Selasky
972d6b92ffaSHans Petter Selasky #define NEIGH_GET_DEFAULT_TIMEOUT_MS 3000
ibv_resolve_eth_l2_from_gid(struct ibv_context * context,struct ibv_ah_attr * attr,uint8_t eth_mac[ETHERNET_LL_SIZE],uint16_t * vid)973d6b92ffaSHans Petter Selasky int ibv_resolve_eth_l2_from_gid(struct ibv_context *context,
974d6b92ffaSHans Petter Selasky struct ibv_ah_attr *attr,
975d6b92ffaSHans Petter Selasky uint8_t eth_mac[ETHERNET_LL_SIZE],
976d6b92ffaSHans Petter Selasky uint16_t *vid)
977d6b92ffaSHans Petter Selasky {
978d6b92ffaSHans Petter Selasky #ifndef NRESOLVE_NEIGH
979d6b92ffaSHans Petter Selasky int dst_family;
980d6b92ffaSHans Petter Selasky int src_family;
981d6b92ffaSHans Petter Selasky int oif;
982d6b92ffaSHans Petter Selasky struct get_neigh_handler neigh_handler;
983d6b92ffaSHans Petter Selasky union ibv_gid sgid;
984d6b92ffaSHans Petter Selasky int ether_len;
985d6b92ffaSHans Petter Selasky struct peer_address src;
986d6b92ffaSHans Petter Selasky struct peer_address dst;
987d6b92ffaSHans Petter Selasky uint16_t ret_vid;
988d6b92ffaSHans Petter Selasky int ret = -EINVAL;
989d6b92ffaSHans Petter Selasky int err;
990d6b92ffaSHans Petter Selasky
991d6b92ffaSHans Petter Selasky err = ibv_query_gid(context, attr->port_num,
992d6b92ffaSHans Petter Selasky attr->grh.sgid_index, &sgid);
993d6b92ffaSHans Petter Selasky
994d6b92ffaSHans Petter Selasky if (err)
995d6b92ffaSHans Petter Selasky return err;
996d6b92ffaSHans Petter Selasky
997d6b92ffaSHans Petter Selasky err = neigh_init_resources(&neigh_handler,
998d6b92ffaSHans Petter Selasky NEIGH_GET_DEFAULT_TIMEOUT_MS);
999d6b92ffaSHans Petter Selasky
1000d6b92ffaSHans Petter Selasky if (err)
1001d6b92ffaSHans Petter Selasky return err;
1002d6b92ffaSHans Petter Selasky
1003d6b92ffaSHans Petter Selasky dst_family = ipv6_addr_v4mapped((struct in6_addr *)attr->grh.dgid.raw) ?
1004d6b92ffaSHans Petter Selasky AF_INET : AF_INET6;
1005d6b92ffaSHans Petter Selasky src_family = ipv6_addr_v4mapped((struct in6_addr *)sgid.raw) ?
1006d6b92ffaSHans Petter Selasky AF_INET : AF_INET6;
1007d6b92ffaSHans Petter Selasky
1008d6b92ffaSHans Petter Selasky if (create_peer_from_gid(dst_family, attr->grh.dgid.raw, &dst))
1009d6b92ffaSHans Petter Selasky goto free_resources;
1010d6b92ffaSHans Petter Selasky
1011d6b92ffaSHans Petter Selasky if (create_peer_from_gid(src_family, &sgid.raw, &src))
1012d6b92ffaSHans Petter Selasky goto free_resources;
1013d6b92ffaSHans Petter Selasky
1014d6b92ffaSHans Petter Selasky if (neigh_set_dst(&neigh_handler, dst_family, dst.address,
1015d6b92ffaSHans Petter Selasky dst.size))
1016d6b92ffaSHans Petter Selasky goto free_resources;
1017d6b92ffaSHans Petter Selasky
1018d6b92ffaSHans Petter Selasky if (neigh_set_src(&neigh_handler, src_family, src.address,
1019d6b92ffaSHans Petter Selasky src.size))
1020d6b92ffaSHans Petter Selasky goto free_resources;
1021d6b92ffaSHans Petter Selasky
1022d6b92ffaSHans Petter Selasky oif = neigh_get_oif_from_src(&neigh_handler);
1023d6b92ffaSHans Petter Selasky
1024d6b92ffaSHans Petter Selasky if (oif > 0)
1025d6b92ffaSHans Petter Selasky neigh_set_oif(&neigh_handler, oif);
1026d6b92ffaSHans Petter Selasky else
1027d6b92ffaSHans Petter Selasky goto free_resources;
1028d6b92ffaSHans Petter Selasky
1029d6b92ffaSHans Petter Selasky ret = -EHOSTUNREACH;
1030d6b92ffaSHans Petter Selasky
1031d6b92ffaSHans Petter Selasky /* blocking call */
1032d6b92ffaSHans Petter Selasky if (process_get_neigh(&neigh_handler))
1033d6b92ffaSHans Petter Selasky goto free_resources;
1034d6b92ffaSHans Petter Selasky
1035d6b92ffaSHans Petter Selasky ret_vid = neigh_get_vlan_id_from_dev(&neigh_handler);
1036d6b92ffaSHans Petter Selasky
1037d6b92ffaSHans Petter Selasky if (ret_vid <= 0xfff)
1038d6b92ffaSHans Petter Selasky neigh_set_vlan_id(&neigh_handler, ret_vid);
1039d6b92ffaSHans Petter Selasky
1040d6b92ffaSHans Petter Selasky /* We are using only Ethernet here */
1041d6b92ffaSHans Petter Selasky ether_len = neigh_get_ll(&neigh_handler,
1042d6b92ffaSHans Petter Selasky eth_mac,
1043d6b92ffaSHans Petter Selasky sizeof(uint8_t) * ETHERNET_LL_SIZE);
1044d6b92ffaSHans Petter Selasky
1045d6b92ffaSHans Petter Selasky if (ether_len <= 0)
1046d6b92ffaSHans Petter Selasky goto free_resources;
1047d6b92ffaSHans Petter Selasky
1048d6b92ffaSHans Petter Selasky *vid = ret_vid;
1049d6b92ffaSHans Petter Selasky
1050d6b92ffaSHans Petter Selasky ret = 0;
1051d6b92ffaSHans Petter Selasky
1052d6b92ffaSHans Petter Selasky free_resources:
1053d6b92ffaSHans Petter Selasky neigh_free_resources(&neigh_handler);
1054d6b92ffaSHans Petter Selasky
1055d6b92ffaSHans Petter Selasky return ret;
1056d6b92ffaSHans Petter Selasky #else
1057d6b92ffaSHans Petter Selasky return -ENOSYS;
1058d6b92ffaSHans Petter Selasky #endif
1059d6b92ffaSHans Petter Selasky }
1060