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