verbs.c revision 321936
1321936Shselasky/* 2321936Shselasky * Copyright (c) 2005 Topspin Communications. All rights reserved. 3321936Shselasky * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. 4321936Shselasky * 5321936Shselasky * This software is available to you under a choice of one of two 6321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 7321936Shselasky * General Public License (GPL) Version 2, available from the file 8321936Shselasky * COPYING in the main directory of this source tree, or the 9321936Shselasky * OpenIB.org BSD license below: 10321936Shselasky * 11321936Shselasky * Redistribution and use in source and binary forms, with or 12321936Shselasky * without modification, are permitted provided that the following 13321936Shselasky * conditions are met: 14321936Shselasky * 15321936Shselasky * - Redistributions of source code must retain the above 16321936Shselasky * copyright notice, this list of conditions and the following 17321936Shselasky * disclaimer. 18321936Shselasky * 19321936Shselasky * - Redistributions in binary form must reproduce the above 20321936Shselasky * copyright notice, this list of conditions and the following 21321936Shselasky * disclaimer in the documentation and/or other materials 22321936Shselasky * provided with the distribution. 23321936Shselasky * 24321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31321936Shselasky * SOFTWARE. 32321936Shselasky */ 33321936Shselasky 34321936Shselasky#define _GNU_SOURCE 35321936Shselasky#include <config.h> 36321936Shselasky 37321936Shselasky#include <infiniband/endian.h> 38321936Shselasky#include <stdio.h> 39321936Shselasky#include <unistd.h> 40321936Shselasky#include <stdlib.h> 41321936Shselasky#include <errno.h> 42321936Shselasky#include <string.h> 43321936Shselasky#include <dirent.h> 44321936Shselasky#include <netinet/in.h> 45321936Shselasky#include <netinet/ip.h> 46321936Shselasky#include <sys/socket.h> 47321936Shselasky 48321936Shselasky#include "ibverbs.h" 49321936Shselasky#ifndef NRESOLVE_NEIGH 50321936Shselasky#include <net/if.h> 51321936Shselasky#include <net/if_arp.h> 52321936Shselasky#include "neigh.h" 53321936Shselasky#endif 54321936Shselasky 55321936Shselasky/* Hack to avoid GCC's -Wmissing-prototypes and the similar error from sparse 56321936Shselasky with these prototypes. Symbol versionining requires the goofy names, the 57321936Shselasky prototype must match the version in verbs.h. 58321936Shselasky */ 59321936Shselaskyint __ibv_query_device(struct ibv_context *context, 60321936Shselasky struct ibv_device_attr *device_attr); 61321936Shselaskyint __ibv_query_port(struct ibv_context *context, uint8_t port_num, 62321936Shselasky struct ibv_port_attr *port_attr); 63321936Shselaskyint __ibv_query_gid(struct ibv_context *context, uint8_t port_num, int index, 64321936Shselasky union ibv_gid *gid); 65321936Shselaskyint __ibv_query_pkey(struct ibv_context *context, uint8_t port_num, int index, 66321936Shselasky __be16 *pkey); 67321936Shselaskystruct ibv_pd *__ibv_alloc_pd(struct ibv_context *context); 68321936Shselaskyint __ibv_dealloc_pd(struct ibv_pd *pd); 69321936Shselaskystruct ibv_mr *__ibv_reg_mr(struct ibv_pd *pd, void *addr, size_t length, 70321936Shselasky int access); 71321936Shselaskyint __ibv_rereg_mr(struct ibv_mr *mr, int flags, struct ibv_pd *pd, void *addr, 72321936Shselasky size_t length, int access); 73321936Shselaskyint __ibv_dereg_mr(struct ibv_mr *mr); 74321936Shselaskystruct ibv_cq *__ibv_create_cq(struct ibv_context *context, int cqe, 75321936Shselasky void *cq_context, 76321936Shselasky struct ibv_comp_channel *channel, 77321936Shselasky int comp_vector); 78321936Shselaskyint __ibv_resize_cq(struct ibv_cq *cq, int cqe); 79321936Shselaskyint __ibv_destroy_cq(struct ibv_cq *cq); 80321936Shselaskyint __ibv_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq, 81321936Shselasky void **cq_context); 82321936Shselaskyvoid __ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents); 83321936Shselaskystruct ibv_srq *__ibv_create_srq(struct ibv_pd *pd, 84321936Shselasky struct ibv_srq_init_attr *srq_init_attr); 85321936Shselaskyint __ibv_modify_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr, 86321936Shselasky int srq_attr_mask); 87321936Shselaskyint __ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr); 88321936Shselaskyint __ibv_destroy_srq(struct ibv_srq *srq); 89321936Shselaskystruct ibv_qp *__ibv_create_qp(struct ibv_pd *pd, 90321936Shselasky struct ibv_qp_init_attr *qp_init_attr); 91321936Shselaskyint __ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask, 92321936Shselasky struct ibv_qp_init_attr *init_attr); 93321936Shselaskyint __ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask); 94321936Shselaskyint __ibv_destroy_qp(struct ibv_qp *qp); 95321936Shselaskystruct ibv_ah *__ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr); 96321936Shselaskyint __ibv_destroy_ah(struct ibv_ah *ah); 97321936Shselaskyint __ibv_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, 98321936Shselasky uint16_t lid); 99321936Shselaskyint __ibv_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, 100321936Shselasky uint16_t lid); 101321936Shselasky 102321936Shselaskyint __attribute__((const)) ibv_rate_to_mult(enum ibv_rate rate) 103321936Shselasky{ 104321936Shselasky switch (rate) { 105321936Shselasky case IBV_RATE_2_5_GBPS: return 1; 106321936Shselasky case IBV_RATE_5_GBPS: return 2; 107321936Shselasky case IBV_RATE_10_GBPS: return 4; 108321936Shselasky case IBV_RATE_20_GBPS: return 8; 109321936Shselasky case IBV_RATE_30_GBPS: return 12; 110321936Shselasky case IBV_RATE_40_GBPS: return 16; 111321936Shselasky case IBV_RATE_60_GBPS: return 24; 112321936Shselasky case IBV_RATE_80_GBPS: return 32; 113321936Shselasky case IBV_RATE_120_GBPS: return 48; 114321936Shselasky default: return -1; 115321936Shselasky } 116321936Shselasky} 117321936Shselasky 118321936Shselaskyenum ibv_rate __attribute__((const)) mult_to_ibv_rate(int mult) 119321936Shselasky{ 120321936Shselasky switch (mult) { 121321936Shselasky case 1: return IBV_RATE_2_5_GBPS; 122321936Shselasky case 2: return IBV_RATE_5_GBPS; 123321936Shselasky case 4: return IBV_RATE_10_GBPS; 124321936Shselasky case 8: return IBV_RATE_20_GBPS; 125321936Shselasky case 12: return IBV_RATE_30_GBPS; 126321936Shselasky case 16: return IBV_RATE_40_GBPS; 127321936Shselasky case 24: return IBV_RATE_60_GBPS; 128321936Shselasky case 32: return IBV_RATE_80_GBPS; 129321936Shselasky case 48: return IBV_RATE_120_GBPS; 130321936Shselasky default: return IBV_RATE_MAX; 131321936Shselasky } 132321936Shselasky} 133321936Shselasky 134321936Shselaskyint __attribute__((const)) ibv_rate_to_mbps(enum ibv_rate rate) 135321936Shselasky{ 136321936Shselasky switch (rate) { 137321936Shselasky case IBV_RATE_2_5_GBPS: return 2500; 138321936Shselasky case IBV_RATE_5_GBPS: return 5000; 139321936Shselasky case IBV_RATE_10_GBPS: return 10000; 140321936Shselasky case IBV_RATE_20_GBPS: return 20000; 141321936Shselasky case IBV_RATE_30_GBPS: return 30000; 142321936Shselasky case IBV_RATE_40_GBPS: return 40000; 143321936Shselasky case IBV_RATE_60_GBPS: return 60000; 144321936Shselasky case IBV_RATE_80_GBPS: return 80000; 145321936Shselasky case IBV_RATE_120_GBPS: return 120000; 146321936Shselasky case IBV_RATE_14_GBPS: return 14062; 147321936Shselasky case IBV_RATE_56_GBPS: return 56250; 148321936Shselasky case IBV_RATE_112_GBPS: return 112500; 149321936Shselasky case IBV_RATE_168_GBPS: return 168750; 150321936Shselasky case IBV_RATE_25_GBPS: return 25781; 151321936Shselasky case IBV_RATE_100_GBPS: return 103125; 152321936Shselasky case IBV_RATE_200_GBPS: return 206250; 153321936Shselasky case IBV_RATE_300_GBPS: return 309375; 154321936Shselasky default: return -1; 155321936Shselasky } 156321936Shselasky} 157321936Shselasky 158321936Shselaskyenum ibv_rate __attribute__((const)) mbps_to_ibv_rate(int mbps) 159321936Shselasky{ 160321936Shselasky switch (mbps) { 161321936Shselasky case 2500: return IBV_RATE_2_5_GBPS; 162321936Shselasky case 5000: return IBV_RATE_5_GBPS; 163321936Shselasky case 10000: return IBV_RATE_10_GBPS; 164321936Shselasky case 20000: return IBV_RATE_20_GBPS; 165321936Shselasky case 30000: return IBV_RATE_30_GBPS; 166321936Shselasky case 40000: return IBV_RATE_40_GBPS; 167321936Shselasky case 60000: return IBV_RATE_60_GBPS; 168321936Shselasky case 80000: return IBV_RATE_80_GBPS; 169321936Shselasky case 120000: return IBV_RATE_120_GBPS; 170321936Shselasky case 14062: return IBV_RATE_14_GBPS; 171321936Shselasky case 56250: return IBV_RATE_56_GBPS; 172321936Shselasky case 112500: return IBV_RATE_112_GBPS; 173321936Shselasky case 168750: return IBV_RATE_168_GBPS; 174321936Shselasky case 25781: return IBV_RATE_25_GBPS; 175321936Shselasky case 103125: return IBV_RATE_100_GBPS; 176321936Shselasky case 206250: return IBV_RATE_200_GBPS; 177321936Shselasky case 309375: return IBV_RATE_300_GBPS; 178321936Shselasky default: return IBV_RATE_MAX; 179321936Shselasky } 180321936Shselasky} 181321936Shselasky 182321936Shselaskyint __ibv_query_device(struct ibv_context *context, 183321936Shselasky struct ibv_device_attr *device_attr) 184321936Shselasky{ 185321936Shselasky return context->ops.query_device(context, device_attr); 186321936Shselasky} 187321936Shselaskydefault_symver(__ibv_query_device, ibv_query_device); 188321936Shselasky 189321936Shselaskyint __ibv_query_port(struct ibv_context *context, uint8_t port_num, 190321936Shselasky struct ibv_port_attr *port_attr) 191321936Shselasky{ 192321936Shselasky return context->ops.query_port(context, port_num, port_attr); 193321936Shselasky} 194321936Shselaskydefault_symver(__ibv_query_port, ibv_query_port); 195321936Shselasky 196321936Shselaskyint __ibv_query_gid(struct ibv_context *context, uint8_t port_num, 197321936Shselasky int index, union ibv_gid *gid) 198321936Shselasky{ 199321936Shselasky char name[24]; 200321936Shselasky char attr[41]; 201321936Shselasky uint16_t val; 202321936Shselasky int i; 203321936Shselasky 204321936Shselasky snprintf(name, sizeof name, "ports/%d/gids/%d", port_num, index); 205321936Shselasky 206321936Shselasky if (ibv_read_sysfs_file(context->device->ibdev_path, name, 207321936Shselasky attr, sizeof attr) < 0) 208321936Shselasky return -1; 209321936Shselasky 210321936Shselasky for (i = 0; i < 8; ++i) { 211321936Shselasky if (sscanf(attr + i * 5, "%hx", &val) != 1) 212321936Shselasky return -1; 213321936Shselasky gid->raw[i * 2 ] = val >> 8; 214321936Shselasky gid->raw[i * 2 + 1] = val & 0xff; 215321936Shselasky } 216321936Shselasky 217321936Shselasky return 0; 218321936Shselasky} 219321936Shselaskydefault_symver(__ibv_query_gid, ibv_query_gid); 220321936Shselasky 221321936Shselaskyint __ibv_query_pkey(struct ibv_context *context, uint8_t port_num, 222321936Shselasky int index, __be16 *pkey) 223321936Shselasky{ 224321936Shselasky char name[24]; 225321936Shselasky char attr[8]; 226321936Shselasky uint16_t val; 227321936Shselasky 228321936Shselasky snprintf(name, sizeof name, "ports/%d/pkeys/%d", port_num, index); 229321936Shselasky 230321936Shselasky if (ibv_read_sysfs_file(context->device->ibdev_path, name, 231321936Shselasky attr, sizeof attr) < 0) 232321936Shselasky return -1; 233321936Shselasky 234321936Shselasky if (sscanf(attr, "%hx", &val) != 1) 235321936Shselasky return -1; 236321936Shselasky 237321936Shselasky *pkey = htobe16(val); 238321936Shselasky return 0; 239321936Shselasky} 240321936Shselaskydefault_symver(__ibv_query_pkey, ibv_query_pkey); 241321936Shselasky 242321936Shselaskystruct ibv_pd *__ibv_alloc_pd(struct ibv_context *context) 243321936Shselasky{ 244321936Shselasky struct ibv_pd *pd; 245321936Shselasky 246321936Shselasky pd = context->ops.alloc_pd(context); 247321936Shselasky if (pd) 248321936Shselasky pd->context = context; 249321936Shselasky 250321936Shselasky return pd; 251321936Shselasky} 252321936Shselaskydefault_symver(__ibv_alloc_pd, ibv_alloc_pd); 253321936Shselasky 254321936Shselaskyint __ibv_dealloc_pd(struct ibv_pd *pd) 255321936Shselasky{ 256321936Shselasky return pd->context->ops.dealloc_pd(pd); 257321936Shselasky} 258321936Shselaskydefault_symver(__ibv_dealloc_pd, ibv_dealloc_pd); 259321936Shselasky 260321936Shselaskystruct ibv_mr *__ibv_reg_mr(struct ibv_pd *pd, void *addr, 261321936Shselasky size_t length, int access) 262321936Shselasky{ 263321936Shselasky struct ibv_mr *mr; 264321936Shselasky 265321936Shselasky if (ibv_dontfork_range(addr, length)) 266321936Shselasky return NULL; 267321936Shselasky 268321936Shselasky mr = pd->context->ops.reg_mr(pd, addr, length, access); 269321936Shselasky if (mr) { 270321936Shselasky mr->context = pd->context; 271321936Shselasky mr->pd = pd; 272321936Shselasky mr->addr = addr; 273321936Shselasky mr->length = length; 274321936Shselasky } else 275321936Shselasky ibv_dofork_range(addr, length); 276321936Shselasky 277321936Shselasky return mr; 278321936Shselasky} 279321936Shselaskydefault_symver(__ibv_reg_mr, ibv_reg_mr); 280321936Shselasky 281321936Shselaskyint __ibv_rereg_mr(struct ibv_mr *mr, int flags, 282321936Shselasky struct ibv_pd *pd, void *addr, 283321936Shselasky size_t length, int access) 284321936Shselasky{ 285321936Shselasky int dofork_onfail = 0; 286321936Shselasky int err; 287321936Shselasky void *old_addr; 288321936Shselasky size_t old_len; 289321936Shselasky 290321936Shselasky if (flags & ~IBV_REREG_MR_FLAGS_SUPPORTED) { 291321936Shselasky errno = EINVAL; 292321936Shselasky return IBV_REREG_MR_ERR_INPUT; 293321936Shselasky } 294321936Shselasky 295321936Shselasky if ((flags & IBV_REREG_MR_CHANGE_TRANSLATION) && 296321936Shselasky (!length || !addr)) { 297321936Shselasky errno = EINVAL; 298321936Shselasky return IBV_REREG_MR_ERR_INPUT; 299321936Shselasky } 300321936Shselasky 301321936Shselasky if (access && !(flags & IBV_REREG_MR_CHANGE_ACCESS)) { 302321936Shselasky errno = EINVAL; 303321936Shselasky return IBV_REREG_MR_ERR_INPUT; 304321936Shselasky } 305321936Shselasky 306321936Shselasky if (!mr->context->ops.rereg_mr) { 307321936Shselasky errno = ENOSYS; 308321936Shselasky return IBV_REREG_MR_ERR_INPUT; 309321936Shselasky } 310321936Shselasky 311321936Shselasky if (flags & IBV_REREG_MR_CHANGE_TRANSLATION) { 312321936Shselasky err = ibv_dontfork_range(addr, length); 313321936Shselasky if (err) 314321936Shselasky return IBV_REREG_MR_ERR_DONT_FORK_NEW; 315321936Shselasky dofork_onfail = 1; 316321936Shselasky } 317321936Shselasky 318321936Shselasky old_addr = mr->addr; 319321936Shselasky old_len = mr->length; 320321936Shselasky err = mr->context->ops.rereg_mr(mr, flags, pd, addr, length, access); 321321936Shselasky if (!err) { 322321936Shselasky if (flags & IBV_REREG_MR_CHANGE_PD) 323321936Shselasky mr->pd = pd; 324321936Shselasky if (flags & IBV_REREG_MR_CHANGE_TRANSLATION) { 325321936Shselasky mr->addr = addr; 326321936Shselasky mr->length = length; 327321936Shselasky err = ibv_dofork_range(old_addr, old_len); 328321936Shselasky if (err) 329321936Shselasky return IBV_REREG_MR_ERR_DO_FORK_OLD; 330321936Shselasky } 331321936Shselasky } else { 332321936Shselasky err = IBV_REREG_MR_ERR_CMD; 333321936Shselasky if (dofork_onfail) { 334321936Shselasky if (ibv_dofork_range(addr, length)) 335321936Shselasky err = IBV_REREG_MR_ERR_CMD_AND_DO_FORK_NEW; 336321936Shselasky } 337321936Shselasky } 338321936Shselasky 339321936Shselasky return err; 340321936Shselasky} 341321936Shselaskydefault_symver(__ibv_rereg_mr, ibv_rereg_mr); 342321936Shselasky 343321936Shselaskyint __ibv_dereg_mr(struct ibv_mr *mr) 344321936Shselasky{ 345321936Shselasky int ret; 346321936Shselasky void *addr = mr->addr; 347321936Shselasky size_t length = mr->length; 348321936Shselasky 349321936Shselasky ret = mr->context->ops.dereg_mr(mr); 350321936Shselasky if (!ret) 351321936Shselasky ibv_dofork_range(addr, length); 352321936Shselasky 353321936Shselasky return ret; 354321936Shselasky} 355321936Shselaskydefault_symver(__ibv_dereg_mr, ibv_dereg_mr); 356321936Shselasky 357321936Shselaskystatic struct ibv_comp_channel *ibv_create_comp_channel_v2(struct ibv_context *context) 358321936Shselasky{ 359321936Shselasky struct ibv_abi_compat_v2 *t = context->abi_compat; 360321936Shselasky static int warned; 361321936Shselasky 362321936Shselasky if (!pthread_mutex_trylock(&t->in_use)) 363321936Shselasky return &t->channel; 364321936Shselasky 365321936Shselasky if (!warned) { 366321936Shselasky fprintf(stderr, PFX "Warning: kernel's ABI version %d limits capacity.\n" 367321936Shselasky " Only one completion channel can be created per context.\n", 368321936Shselasky abi_ver); 369321936Shselasky ++warned; 370321936Shselasky } 371321936Shselasky 372321936Shselasky return NULL; 373321936Shselasky} 374321936Shselasky 375321936Shselaskystruct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context) 376321936Shselasky{ 377321936Shselasky struct ibv_comp_channel *channel; 378321936Shselasky struct ibv_create_comp_channel cmd; 379321936Shselasky struct ibv_create_comp_channel_resp resp; 380321936Shselasky 381321936Shselasky if (abi_ver <= 2) 382321936Shselasky return ibv_create_comp_channel_v2(context); 383321936Shselasky 384321936Shselasky channel = malloc(sizeof *channel); 385321936Shselasky if (!channel) 386321936Shselasky return NULL; 387321936Shselasky 388321936Shselasky IBV_INIT_CMD_RESP(&cmd, sizeof cmd, CREATE_COMP_CHANNEL, &resp, sizeof resp); 389321936Shselasky if (write(context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) { 390321936Shselasky free(channel); 391321936Shselasky return NULL; 392321936Shselasky } 393321936Shselasky 394321936Shselasky (void) VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); 395321936Shselasky 396321936Shselasky channel->context = context; 397321936Shselasky channel->fd = resp.fd; 398321936Shselasky channel->refcnt = 0; 399321936Shselasky 400321936Shselasky return channel; 401321936Shselasky} 402321936Shselasky 403321936Shselaskystatic int ibv_destroy_comp_channel_v2(struct ibv_comp_channel *channel) 404321936Shselasky{ 405321936Shselasky struct ibv_abi_compat_v2 *t = (struct ibv_abi_compat_v2 *) channel; 406321936Shselasky pthread_mutex_unlock(&t->in_use); 407321936Shselasky return 0; 408321936Shselasky} 409321936Shselasky 410321936Shselaskyint ibv_destroy_comp_channel(struct ibv_comp_channel *channel) 411321936Shselasky{ 412321936Shselasky struct ibv_context *context; 413321936Shselasky int ret; 414321936Shselasky 415321936Shselasky context = channel->context; 416321936Shselasky pthread_mutex_lock(&context->mutex); 417321936Shselasky 418321936Shselasky if (channel->refcnt) { 419321936Shselasky ret = EBUSY; 420321936Shselasky goto out; 421321936Shselasky } 422321936Shselasky 423321936Shselasky if (abi_ver <= 2) { 424321936Shselasky ret = ibv_destroy_comp_channel_v2(channel); 425321936Shselasky goto out; 426321936Shselasky } 427321936Shselasky 428321936Shselasky close(channel->fd); 429321936Shselasky free(channel); 430321936Shselasky ret = 0; 431321936Shselasky 432321936Shselaskyout: 433321936Shselasky pthread_mutex_unlock(&context->mutex); 434321936Shselasky 435321936Shselasky return ret; 436321936Shselasky} 437321936Shselasky 438321936Shselaskystruct ibv_cq *__ibv_create_cq(struct ibv_context *context, int cqe, void *cq_context, 439321936Shselasky struct ibv_comp_channel *channel, int comp_vector) 440321936Shselasky{ 441321936Shselasky struct ibv_cq *cq; 442321936Shselasky 443321936Shselasky cq = context->ops.create_cq(context, cqe, channel, comp_vector); 444321936Shselasky 445321936Shselasky if (cq) 446321936Shselasky verbs_init_cq(cq, context, channel, cq_context); 447321936Shselasky 448321936Shselasky return cq; 449321936Shselasky} 450321936Shselaskydefault_symver(__ibv_create_cq, ibv_create_cq); 451321936Shselasky 452321936Shselaskyint __ibv_resize_cq(struct ibv_cq *cq, int cqe) 453321936Shselasky{ 454321936Shselasky if (!cq->context->ops.resize_cq) 455321936Shselasky return ENOSYS; 456321936Shselasky 457321936Shselasky return cq->context->ops.resize_cq(cq, cqe); 458321936Shselasky} 459321936Shselaskydefault_symver(__ibv_resize_cq, ibv_resize_cq); 460321936Shselasky 461321936Shselaskyint __ibv_destroy_cq(struct ibv_cq *cq) 462321936Shselasky{ 463321936Shselasky struct ibv_comp_channel *channel = cq->channel; 464321936Shselasky int ret; 465321936Shselasky 466321936Shselasky ret = cq->context->ops.destroy_cq(cq); 467321936Shselasky 468321936Shselasky if (channel) { 469321936Shselasky if (!ret) { 470321936Shselasky pthread_mutex_lock(&channel->context->mutex); 471321936Shselasky --channel->refcnt; 472321936Shselasky pthread_mutex_unlock(&channel->context->mutex); 473321936Shselasky } 474321936Shselasky } 475321936Shselasky 476321936Shselasky return ret; 477321936Shselasky} 478321936Shselaskydefault_symver(__ibv_destroy_cq, ibv_destroy_cq); 479321936Shselasky 480321936Shselaskyint __ibv_get_cq_event(struct ibv_comp_channel *channel, 481321936Shselasky struct ibv_cq **cq, void **cq_context) 482321936Shselasky{ 483321936Shselasky struct ibv_comp_event ev; 484321936Shselasky 485321936Shselasky if (read(channel->fd, &ev, sizeof ev) != sizeof ev) 486321936Shselasky return -1; 487321936Shselasky 488321936Shselasky *cq = (struct ibv_cq *) (uintptr_t) ev.cq_handle; 489321936Shselasky *cq_context = (*cq)->cq_context; 490321936Shselasky 491321936Shselasky if ((*cq)->context->ops.cq_event) 492321936Shselasky (*cq)->context->ops.cq_event(*cq); 493321936Shselasky 494321936Shselasky return 0; 495321936Shselasky} 496321936Shselaskydefault_symver(__ibv_get_cq_event, ibv_get_cq_event); 497321936Shselasky 498321936Shselaskyvoid __ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents) 499321936Shselasky{ 500321936Shselasky pthread_mutex_lock(&cq->mutex); 501321936Shselasky cq->comp_events_completed += nevents; 502321936Shselasky pthread_cond_signal(&cq->cond); 503321936Shselasky pthread_mutex_unlock(&cq->mutex); 504321936Shselasky} 505321936Shselaskydefault_symver(__ibv_ack_cq_events, ibv_ack_cq_events); 506321936Shselasky 507321936Shselaskystruct ibv_srq *__ibv_create_srq(struct ibv_pd *pd, 508321936Shselasky struct ibv_srq_init_attr *srq_init_attr) 509321936Shselasky{ 510321936Shselasky struct ibv_srq *srq; 511321936Shselasky 512321936Shselasky if (!pd->context->ops.create_srq) 513321936Shselasky return NULL; 514321936Shselasky 515321936Shselasky srq = pd->context->ops.create_srq(pd, srq_init_attr); 516321936Shselasky if (srq) { 517321936Shselasky srq->context = pd->context; 518321936Shselasky srq->srq_context = srq_init_attr->srq_context; 519321936Shselasky srq->pd = pd; 520321936Shselasky srq->events_completed = 0; 521321936Shselasky pthread_mutex_init(&srq->mutex, NULL); 522321936Shselasky pthread_cond_init(&srq->cond, NULL); 523321936Shselasky } 524321936Shselasky 525321936Shselasky return srq; 526321936Shselasky} 527321936Shselaskydefault_symver(__ibv_create_srq, ibv_create_srq); 528321936Shselasky 529321936Shselaskyint __ibv_modify_srq(struct ibv_srq *srq, 530321936Shselasky struct ibv_srq_attr *srq_attr, 531321936Shselasky int srq_attr_mask) 532321936Shselasky{ 533321936Shselasky return srq->context->ops.modify_srq(srq, srq_attr, srq_attr_mask); 534321936Shselasky} 535321936Shselaskydefault_symver(__ibv_modify_srq, ibv_modify_srq); 536321936Shselasky 537321936Shselaskyint __ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr) 538321936Shselasky{ 539321936Shselasky return srq->context->ops.query_srq(srq, srq_attr); 540321936Shselasky} 541321936Shselaskydefault_symver(__ibv_query_srq, ibv_query_srq); 542321936Shselasky 543321936Shselaskyint __ibv_destroy_srq(struct ibv_srq *srq) 544321936Shselasky{ 545321936Shselasky return srq->context->ops.destroy_srq(srq); 546321936Shselasky} 547321936Shselaskydefault_symver(__ibv_destroy_srq, ibv_destroy_srq); 548321936Shselasky 549321936Shselaskystruct ibv_qp *__ibv_create_qp(struct ibv_pd *pd, 550321936Shselasky struct ibv_qp_init_attr *qp_init_attr) 551321936Shselasky{ 552321936Shselasky struct ibv_qp *qp = pd->context->ops.create_qp(pd, qp_init_attr); 553321936Shselasky 554321936Shselasky if (qp) { 555321936Shselasky qp->context = pd->context; 556321936Shselasky qp->qp_context = qp_init_attr->qp_context; 557321936Shselasky qp->pd = pd; 558321936Shselasky qp->send_cq = qp_init_attr->send_cq; 559321936Shselasky qp->recv_cq = qp_init_attr->recv_cq; 560321936Shselasky qp->srq = qp_init_attr->srq; 561321936Shselasky qp->qp_type = qp_init_attr->qp_type; 562321936Shselasky qp->state = IBV_QPS_RESET; 563321936Shselasky qp->events_completed = 0; 564321936Shselasky pthread_mutex_init(&qp->mutex, NULL); 565321936Shselasky pthread_cond_init(&qp->cond, NULL); 566321936Shselasky } 567321936Shselasky 568321936Shselasky return qp; 569321936Shselasky} 570321936Shselaskydefault_symver(__ibv_create_qp, ibv_create_qp); 571321936Shselasky 572321936Shselaskyint __ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, 573321936Shselasky int attr_mask, 574321936Shselasky struct ibv_qp_init_attr *init_attr) 575321936Shselasky{ 576321936Shselasky int ret; 577321936Shselasky 578321936Shselasky ret = qp->context->ops.query_qp(qp, attr, attr_mask, init_attr); 579321936Shselasky if (ret) 580321936Shselasky return ret; 581321936Shselasky 582321936Shselasky if (attr_mask & IBV_QP_STATE) 583321936Shselasky qp->state = attr->qp_state; 584321936Shselasky 585321936Shselasky return 0; 586321936Shselasky} 587321936Shselaskydefault_symver(__ibv_query_qp, ibv_query_qp); 588321936Shselasky 589321936Shselaskyint __ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, 590321936Shselasky int attr_mask) 591321936Shselasky{ 592321936Shselasky int ret; 593321936Shselasky 594321936Shselasky ret = qp->context->ops.modify_qp(qp, attr, attr_mask); 595321936Shselasky if (ret) 596321936Shselasky return ret; 597321936Shselasky 598321936Shselasky if (attr_mask & IBV_QP_STATE) 599321936Shselasky qp->state = attr->qp_state; 600321936Shselasky 601321936Shselasky return 0; 602321936Shselasky} 603321936Shselaskydefault_symver(__ibv_modify_qp, ibv_modify_qp); 604321936Shselasky 605321936Shselaskyint __ibv_destroy_qp(struct ibv_qp *qp) 606321936Shselasky{ 607321936Shselasky return qp->context->ops.destroy_qp(qp); 608321936Shselasky} 609321936Shselaskydefault_symver(__ibv_destroy_qp, ibv_destroy_qp); 610321936Shselasky 611321936Shselaskystruct ibv_ah *__ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr) 612321936Shselasky{ 613321936Shselasky struct ibv_ah *ah = pd->context->ops.create_ah(pd, attr); 614321936Shselasky 615321936Shselasky if (ah) { 616321936Shselasky ah->context = pd->context; 617321936Shselasky ah->pd = pd; 618321936Shselasky } 619321936Shselasky 620321936Shselasky return ah; 621321936Shselasky} 622321936Shselaskydefault_symver(__ibv_create_ah, ibv_create_ah); 623321936Shselasky 624321936Shselasky/* GID types as appear in sysfs, no change is expected as of ABI 625321936Shselasky * compatibility. 626321936Shselasky */ 627321936Shselasky#define V1_TYPE "IB/RoCE v1" 628321936Shselasky#define V2_TYPE "RoCE v2" 629321936Shselaskyint ibv_query_gid_type(struct ibv_context *context, uint8_t port_num, 630321936Shselasky unsigned int index, enum ibv_gid_type *type) 631321936Shselasky{ 632321936Shselasky char name[32]; 633321936Shselasky char buff[11]; 634321936Shselasky 635321936Shselasky snprintf(name, sizeof(name), "ports/%d/gid_attrs/types/%d", port_num, 636321936Shselasky index); 637321936Shselasky 638321936Shselasky /* Reset errno so that we can rely on its value upon any error flow in 639321936Shselasky * ibv_read_sysfs_file. 640321936Shselasky */ 641321936Shselasky errno = 0; 642321936Shselasky if (ibv_read_sysfs_file(context->device->ibdev_path, name, buff, 643321936Shselasky sizeof(buff)) <= 0) { 644321936Shselasky char *dir_path; 645321936Shselasky DIR *dir; 646321936Shselasky 647321936Shselasky if (errno == EINVAL) { 648321936Shselasky /* In IB, this file doesn't exist and the kernel sets 649321936Shselasky * errno to -EINVAL. 650321936Shselasky */ 651321936Shselasky *type = IBV_GID_TYPE_IB_ROCE_V1; 652321936Shselasky return 0; 653321936Shselasky } 654321936Shselasky if (asprintf(&dir_path, "%s/%s/%d/%s/", 655321936Shselasky context->device->ibdev_path, "ports", port_num, 656321936Shselasky "gid_attrs") < 0) 657321936Shselasky return -1; 658321936Shselasky dir = opendir(dir_path); 659321936Shselasky free(dir_path); 660321936Shselasky if (!dir) { 661321936Shselasky if (errno == ENOENT) 662321936Shselasky /* Assuming that if gid_attrs doesn't exist, 663321936Shselasky * we have an old kernel and all GIDs are 664321936Shselasky * IB/RoCE v1 665321936Shselasky */ 666321936Shselasky *type = IBV_GID_TYPE_IB_ROCE_V1; 667321936Shselasky else 668321936Shselasky return -1; 669321936Shselasky } else { 670321936Shselasky closedir(dir); 671321936Shselasky errno = EFAULT; 672321936Shselasky return -1; 673321936Shselasky } 674321936Shselasky } else { 675321936Shselasky if (!strcmp(buff, V1_TYPE)) { 676321936Shselasky *type = IBV_GID_TYPE_IB_ROCE_V1; 677321936Shselasky } else if (!strcmp(buff, V2_TYPE)) { 678321936Shselasky *type = IBV_GID_TYPE_ROCE_V2; 679321936Shselasky } else { 680321936Shselasky errno = ENOTSUP; 681321936Shselasky return -1; 682321936Shselasky } 683321936Shselasky } 684321936Shselasky 685321936Shselasky return 0; 686321936Shselasky} 687321936Shselasky 688321936Shselaskystatic int ibv_find_gid_index(struct ibv_context *context, uint8_t port_num, 689321936Shselasky union ibv_gid *gid, enum ibv_gid_type gid_type) 690321936Shselasky{ 691321936Shselasky enum ibv_gid_type sgid_type = 0; 692321936Shselasky union ibv_gid sgid; 693321936Shselasky int i = 0, ret; 694321936Shselasky 695321936Shselasky do { 696321936Shselasky ret = ibv_query_gid(context, port_num, i, &sgid); 697321936Shselasky if (!ret) { 698321936Shselasky ret = ibv_query_gid_type(context, port_num, i, 699321936Shselasky &sgid_type); 700321936Shselasky } 701321936Shselasky i++; 702321936Shselasky } while (!ret && (memcmp(&sgid, gid, sizeof(*gid)) || 703321936Shselasky (gid_type != sgid_type))); 704321936Shselasky 705321936Shselasky return ret ? ret : i - 1; 706321936Shselasky} 707321936Shselasky 708321936Shselaskystatic inline void map_ipv4_addr_to_ipv6(__be32 ipv4, struct in6_addr *ipv6) 709321936Shselasky{ 710321936Shselasky ipv6->s6_addr32[0] = 0; 711321936Shselasky ipv6->s6_addr32[1] = 0; 712321936Shselasky ipv6->s6_addr32[2] = htobe32(0x0000FFFF); 713321936Shselasky ipv6->s6_addr32[3] = ipv4; 714321936Shselasky} 715321936Shselasky 716321936Shselaskystatic inline __sum16 ipv4_calc_hdr_csum(uint16_t *data, unsigned int num_hwords) 717321936Shselasky{ 718321936Shselasky unsigned int i = 0; 719321936Shselasky uint32_t sum = 0; 720321936Shselasky 721321936Shselasky for (i = 0; i < num_hwords; i++) 722321936Shselasky sum += *(data++); 723321936Shselasky 724321936Shselasky sum = (sum & 0xffff) + (sum >> 16); 725321936Shselasky 726321936Shselasky return (__sum16)~sum; 727321936Shselasky} 728321936Shselasky 729321936Shselaskystatic inline int get_grh_header_version(struct ibv_grh *grh) 730321936Shselasky{ 731321936Shselasky int ip6h_version = (be32toh(grh->version_tclass_flow) >> 28) & 0xf; 732321936Shselasky struct ip *ip4h = (struct ip *)((void *)grh + 20); 733321936Shselasky struct ip ip4h_checked; 734321936Shselasky 735321936Shselasky if (ip6h_version != 6) { 736321936Shselasky if (ip4h->ip_v == 4) 737321936Shselasky return 4; 738321936Shselasky errno = EPROTONOSUPPORT; 739321936Shselasky return -1; 740321936Shselasky } 741321936Shselasky /* version may be 6 or 4 */ 742321936Shselasky if (ip4h->ip_hl != 5) /* IPv4 header length must be 5 for RoCE v2. */ 743321936Shselasky return 6; 744321936Shselasky /* 745321936Shselasky * Verify checksum. 746321936Shselasky * We can't write on scattered buffers so we have to copy to temp 747321936Shselasky * buffer. 748321936Shselasky */ 749321936Shselasky memcpy(&ip4h_checked, ip4h, sizeof(ip4h_checked)); 750321936Shselasky /* Need to set the checksum field (check) to 0 before re-calculating 751321936Shselasky * the checksum. 752321936Shselasky */ 753321936Shselasky ip4h_checked.ip_sum = 0; 754321936Shselasky ip4h_checked.ip_sum = ipv4_calc_hdr_csum((uint16_t *)&ip4h_checked, 10); 755321936Shselasky /* if IPv4 header checksum is OK, believe it */ 756321936Shselasky if (ip4h->ip_sum == ip4h_checked.ip_sum) 757321936Shselasky return 4; 758321936Shselasky return 6; 759321936Shselasky} 760321936Shselasky 761321936Shselaskystatic inline void set_ah_attr_generic_fields(struct ibv_ah_attr *ah_attr, 762321936Shselasky struct ibv_wc *wc, 763321936Shselasky struct ibv_grh *grh, 764321936Shselasky uint8_t port_num) 765321936Shselasky{ 766321936Shselasky uint32_t flow_class; 767321936Shselasky 768321936Shselasky flow_class = be32toh(grh->version_tclass_flow); 769321936Shselasky ah_attr->grh.flow_label = flow_class & 0xFFFFF; 770321936Shselasky ah_attr->dlid = wc->slid; 771321936Shselasky ah_attr->sl = wc->sl; 772321936Shselasky ah_attr->src_path_bits = wc->dlid_path_bits; 773321936Shselasky ah_attr->port_num = port_num; 774321936Shselasky} 775321936Shselasky 776321936Shselaskystatic inline int set_ah_attr_by_ipv4(struct ibv_context *context, 777321936Shselasky struct ibv_ah_attr *ah_attr, 778321936Shselasky struct ip *ip4h, uint8_t port_num) 779321936Shselasky{ 780321936Shselasky union ibv_gid sgid; 781321936Shselasky int ret; 782321936Shselasky 783321936Shselasky /* No point searching multicast GIDs in GID table */ 784321936Shselasky if (IN_CLASSD(be32toh(ip4h->ip_dst.s_addr))) { 785321936Shselasky errno = EINVAL; 786321936Shselasky return -1; 787321936Shselasky } 788321936Shselasky 789321936Shselasky map_ipv4_addr_to_ipv6(ip4h->ip_dst.s_addr, (struct in6_addr *)&sgid); 790321936Shselasky ret = ibv_find_gid_index(context, port_num, &sgid, 791321936Shselasky IBV_GID_TYPE_ROCE_V2); 792321936Shselasky if (ret < 0) 793321936Shselasky return ret; 794321936Shselasky 795321936Shselasky map_ipv4_addr_to_ipv6(ip4h->ip_src.s_addr, 796321936Shselasky (struct in6_addr *)&ah_attr->grh.dgid); 797321936Shselasky ah_attr->grh.sgid_index = (uint8_t) ret; 798321936Shselasky ah_attr->grh.hop_limit = ip4h->ip_ttl; 799321936Shselasky ah_attr->grh.traffic_class = ip4h->ip_tos; 800321936Shselasky 801321936Shselasky return 0; 802321936Shselasky} 803321936Shselasky 804321936Shselasky#define IB_NEXT_HDR 0x1b 805321936Shselaskystatic inline int set_ah_attr_by_ipv6(struct ibv_context *context, 806321936Shselasky struct ibv_ah_attr *ah_attr, 807321936Shselasky struct ibv_grh *grh, uint8_t port_num) 808321936Shselasky{ 809321936Shselasky uint32_t flow_class; 810321936Shselasky uint32_t sgid_type; 811321936Shselasky int ret; 812321936Shselasky 813321936Shselasky /* No point searching multicast GIDs in GID table */ 814321936Shselasky if (grh->dgid.raw[0] == 0xFF) { 815321936Shselasky errno = EINVAL; 816321936Shselasky return -1; 817321936Shselasky } 818321936Shselasky 819321936Shselasky ah_attr->grh.dgid = grh->sgid; 820321936Shselasky if (grh->next_hdr == IPPROTO_UDP) { 821321936Shselasky sgid_type = IBV_GID_TYPE_ROCE_V2; 822321936Shselasky } else if (grh->next_hdr == IB_NEXT_HDR) { 823321936Shselasky sgid_type = IBV_GID_TYPE_IB_ROCE_V1; 824321936Shselasky } else { 825321936Shselasky errno = EPROTONOSUPPORT; 826321936Shselasky return -1; 827321936Shselasky } 828321936Shselasky 829321936Shselasky ret = ibv_find_gid_index(context, port_num, &grh->dgid, 830321936Shselasky sgid_type); 831321936Shselasky if (ret < 0) 832321936Shselasky return ret; 833321936Shselasky 834321936Shselasky ah_attr->grh.sgid_index = (uint8_t) ret; 835321936Shselasky flow_class = be32toh(grh->version_tclass_flow); 836321936Shselasky ah_attr->grh.hop_limit = grh->hop_limit; 837321936Shselasky ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF; 838321936Shselasky 839321936Shselasky return 0; 840321936Shselasky} 841321936Shselasky 842321936Shselaskyint ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num, 843321936Shselasky struct ibv_wc *wc, struct ibv_grh *grh, 844321936Shselasky struct ibv_ah_attr *ah_attr) 845321936Shselasky{ 846321936Shselasky int version; 847321936Shselasky int ret = 0; 848321936Shselasky 849321936Shselasky memset(ah_attr, 0, sizeof *ah_attr); 850321936Shselasky set_ah_attr_generic_fields(ah_attr, wc, grh, port_num); 851321936Shselasky 852321936Shselasky if (wc->wc_flags & IBV_WC_GRH) { 853321936Shselasky ah_attr->is_global = 1; 854321936Shselasky version = get_grh_header_version(grh); 855321936Shselasky 856321936Shselasky if (version == 4) 857321936Shselasky ret = set_ah_attr_by_ipv4(context, ah_attr, 858321936Shselasky (struct ip *)((void *)grh + 20), 859321936Shselasky port_num); 860321936Shselasky else if (version == 6) 861321936Shselasky ret = set_ah_attr_by_ipv6(context, ah_attr, grh, 862321936Shselasky port_num); 863321936Shselasky else 864321936Shselasky ret = -1; 865321936Shselasky } 866321936Shselasky 867321936Shselasky return ret; 868321936Shselasky} 869321936Shselasky 870321936Shselaskystruct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc, 871321936Shselasky struct ibv_grh *grh, uint8_t port_num) 872321936Shselasky{ 873321936Shselasky struct ibv_ah_attr ah_attr; 874321936Shselasky int ret; 875321936Shselasky 876321936Shselasky ret = ibv_init_ah_from_wc(pd->context, port_num, wc, grh, &ah_attr); 877321936Shselasky if (ret) 878321936Shselasky return NULL; 879321936Shselasky 880321936Shselasky return ibv_create_ah(pd, &ah_attr); 881321936Shselasky} 882321936Shselasky 883321936Shselaskyint __ibv_destroy_ah(struct ibv_ah *ah) 884321936Shselasky{ 885321936Shselasky return ah->context->ops.destroy_ah(ah); 886321936Shselasky} 887321936Shselaskydefault_symver(__ibv_destroy_ah, ibv_destroy_ah); 888321936Shselasky 889321936Shselaskyint __ibv_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid) 890321936Shselasky{ 891321936Shselasky return qp->context->ops.attach_mcast(qp, gid, lid); 892321936Shselasky} 893321936Shselaskydefault_symver(__ibv_attach_mcast, ibv_attach_mcast); 894321936Shselasky 895321936Shselaskyint __ibv_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid) 896321936Shselasky{ 897321936Shselasky return qp->context->ops.detach_mcast(qp, gid, lid); 898321936Shselasky} 899321936Shselaskydefault_symver(__ibv_detach_mcast, ibv_detach_mcast); 900321936Shselasky 901321936Shselaskystatic inline int ipv6_addr_v4mapped(const struct in6_addr *a) 902321936Shselasky{ 903321936Shselasky return IN6_IS_ADDR_V4MAPPED(a) || 904321936Shselasky /* IPv4 encoded multicast addresses */ 905321936Shselasky (a->s6_addr32[0] == htobe32(0xff0e0000) && 906321936Shselasky ((a->s6_addr32[1] | 907321936Shselasky (a->s6_addr32[2] ^ htobe32(0x0000ffff))) == 0UL)); 908321936Shselasky} 909321936Shselasky 910321936Shselaskystruct peer_address { 911321936Shselasky void *address; 912321936Shselasky uint32_t size; 913321936Shselasky}; 914321936Shselasky 915321936Shselaskystatic inline int create_peer_from_gid(int family, void *raw_gid, 916321936Shselasky struct peer_address *peer_address) 917321936Shselasky{ 918321936Shselasky switch (family) { 919321936Shselasky case AF_INET: 920321936Shselasky peer_address->address = raw_gid + 12; 921321936Shselasky peer_address->size = 4; 922321936Shselasky break; 923321936Shselasky case AF_INET6: 924321936Shselasky peer_address->address = raw_gid; 925321936Shselasky peer_address->size = 16; 926321936Shselasky break; 927321936Shselasky default: 928321936Shselasky return -1; 929321936Shselasky } 930321936Shselasky 931321936Shselasky return 0; 932321936Shselasky} 933321936Shselasky 934321936Shselasky#define NEIGH_GET_DEFAULT_TIMEOUT_MS 3000 935321936Shselaskyint ibv_resolve_eth_l2_from_gid(struct ibv_context *context, 936321936Shselasky struct ibv_ah_attr *attr, 937321936Shselasky uint8_t eth_mac[ETHERNET_LL_SIZE], 938321936Shselasky uint16_t *vid) 939321936Shselasky{ 940321936Shselasky#ifndef NRESOLVE_NEIGH 941321936Shselasky int dst_family; 942321936Shselasky int src_family; 943321936Shselasky int oif; 944321936Shselasky struct get_neigh_handler neigh_handler; 945321936Shselasky union ibv_gid sgid; 946321936Shselasky int ether_len; 947321936Shselasky struct peer_address src; 948321936Shselasky struct peer_address dst; 949321936Shselasky uint16_t ret_vid; 950321936Shselasky int ret = -EINVAL; 951321936Shselasky int err; 952321936Shselasky 953321936Shselasky err = ibv_query_gid(context, attr->port_num, 954321936Shselasky attr->grh.sgid_index, &sgid); 955321936Shselasky 956321936Shselasky if (err) 957321936Shselasky return err; 958321936Shselasky 959321936Shselasky err = neigh_init_resources(&neigh_handler, 960321936Shselasky NEIGH_GET_DEFAULT_TIMEOUT_MS); 961321936Shselasky 962321936Shselasky if (err) 963321936Shselasky return err; 964321936Shselasky 965321936Shselasky dst_family = ipv6_addr_v4mapped((struct in6_addr *)attr->grh.dgid.raw) ? 966321936Shselasky AF_INET : AF_INET6; 967321936Shselasky src_family = ipv6_addr_v4mapped((struct in6_addr *)sgid.raw) ? 968321936Shselasky AF_INET : AF_INET6; 969321936Shselasky 970321936Shselasky if (create_peer_from_gid(dst_family, attr->grh.dgid.raw, &dst)) 971321936Shselasky goto free_resources; 972321936Shselasky 973321936Shselasky if (create_peer_from_gid(src_family, &sgid.raw, &src)) 974321936Shselasky goto free_resources; 975321936Shselasky 976321936Shselasky if (neigh_set_dst(&neigh_handler, dst_family, dst.address, 977321936Shselasky dst.size)) 978321936Shselasky goto free_resources; 979321936Shselasky 980321936Shselasky if (neigh_set_src(&neigh_handler, src_family, src.address, 981321936Shselasky src.size)) 982321936Shselasky goto free_resources; 983321936Shselasky 984321936Shselasky oif = neigh_get_oif_from_src(&neigh_handler); 985321936Shselasky 986321936Shselasky if (oif > 0) 987321936Shselasky neigh_set_oif(&neigh_handler, oif); 988321936Shselasky else 989321936Shselasky goto free_resources; 990321936Shselasky 991321936Shselasky ret = -EHOSTUNREACH; 992321936Shselasky 993321936Shselasky /* blocking call */ 994321936Shselasky if (process_get_neigh(&neigh_handler)) 995321936Shselasky goto free_resources; 996321936Shselasky 997321936Shselasky ret_vid = neigh_get_vlan_id_from_dev(&neigh_handler); 998321936Shselasky 999321936Shselasky if (ret_vid <= 0xfff) 1000321936Shselasky neigh_set_vlan_id(&neigh_handler, ret_vid); 1001321936Shselasky 1002321936Shselasky /* We are using only Ethernet here */ 1003321936Shselasky ether_len = neigh_get_ll(&neigh_handler, 1004321936Shselasky eth_mac, 1005321936Shselasky sizeof(uint8_t) * ETHERNET_LL_SIZE); 1006321936Shselasky 1007321936Shselasky if (ether_len <= 0) 1008321936Shselasky goto free_resources; 1009321936Shselasky 1010321936Shselasky *vid = ret_vid; 1011321936Shselasky 1012321936Shselasky ret = 0; 1013321936Shselasky 1014321936Shselaskyfree_resources: 1015321936Shselasky neigh_free_resources(&neigh_handler); 1016321936Shselasky 1017321936Shselasky return ret; 1018321936Shselasky#else 1019321936Shselasky return -ENOSYS; 1020321936Shselasky#endif 1021321936Shselasky} 1022