[PATCH 12/12] libibverbs: port RU examples to explicitly granted resources

From: Doug Ledford

Date: Sat Oct 31 2026 - 15:28:48 EST


Teach ibv_ru_pingpong and ibv_ru_rma to run on a Slingshot device.

CXI has no implicit resources and the service and job grant that
authorise them can only be created by root. On a Slingshot transport
a program that finds no grant (UET_JOB_FD unset) runs itself again
under cxi_launcher, which creates the grant and then runs the program
as the sudo user. The second run finds the grant, allocates its LNI,
PD and PID from it, imports the job and runs the test. A user
starts it with "sudo ibv_ru_pingpong -d DEV ..." and, as with
ibv_ru_rma, may choose the JobID (the VNI) with -j. The launcher
is found next to the program or in the install bindir, never through
PATH. Other transports use the existing code path.

The programs no longer create a service of their own. The SGE count
is checked against the device maximum instead of a fixed constant,
and devinfo reports the Slingshot transport and GID type names.

The Slingshot path uses the cxidv API. It, and the link against
libcxiverbs, is built only when the CXI provider is, which requires
HAVE_COHERENT_DMA; elsewhere the examples build without it.

UET ABI decision needed: this keeps the RU examples, and the generic
pyverbs.ru module, available on platforms without coherent DMA. If
UET, and by extension the RU queue pair type, is not expected to
support such platforms, the RU examples and pyverbs.ru should instead
be built only when HAVE_COHERENT_DMA is set, as the mlx5 and efa
pyverbs modules are.

Co-developed-by: Iraimani P <iraimani.pavadai@xxxxxxx>
Signed-off-by: Iraimani P <iraimani.pavadai@xxxxxxx>
Signed-off-by: Doug Ledford <doug.ledford@xxxxxxx>
---
libibverbs/examples/CMakeLists.txt | 10 +++
libibverbs/examples/devinfo.c | 2 +
libibverbs/examples/ru_cxi_launch.h | 138 ++++++++++++++++++++++++++++++++++++
libibverbs/examples/ru_pingpong.c | 126 ++++++++++++++++++++++++++++----
libibverbs/examples/ru_rma.c | 112 +++++++++++++++++++++++++----
5 files changed, 361 insertions(+), 27 deletions(-)

diff --git a/libibverbs/examples/CMakeLists.txt b/libibverbs/examples/CMakeLists.txt
index a3e5c26ac190..e2134f3e963c 100644
--- a/libibverbs/examples/CMakeLists.txt
+++ b/libibverbs/examples/CMakeLists.txt
@@ -25,6 +25,16 @@ target_link_libraries(ibv_ru_pingpong LINK_PRIVATE ibverbs ibverbs_tools)
rdma_executable(ibv_ru_rma ru_rma.c)
target_link_libraries(ibv_ru_rma LINK_PRIVATE ibverbs ibverbs_tools)

+# CXI is only built with coherent DMA. The examples run themselves again
+# under cxi_launcher on Slingshot devices.
+if (HAVE_COHERENT_DMA)
+ foreach(ru_example ibv_ru_pingpong ibv_ru_rma)
+ target_link_libraries(${ru_example} LINK_PRIVATE cxiverbs)
+ target_compile_definitions(${ru_example} PRIVATE HAVE_CXIVERBS
+ CXI_LAUNCHER_BINDIR="${CMAKE_INSTALL_FULL_BINDIR}")
+ endforeach()
+endif()
+
rdma_executable(ibv_srq_pingpong srq_pingpong.c)
target_link_libraries(ibv_srq_pingpong LINK_PRIVATE ibverbs ibverbs_tools)

diff --git a/libibverbs/examples/devinfo.c b/libibverbs/examples/devinfo.c
index c10c8e21f64a..eb87b3c40d1d 100644
--- a/libibverbs/examples/devinfo.c
+++ b/libibverbs/examples/devinfo.c
@@ -72,6 +72,7 @@ static const char *transport_str(enum ibv_transport_type transport)
case IBV_TRANSPORT_USNIC: return "usNIC";
case IBV_TRANSPORT_USNIC_UDP: return "usNIC UDP";
case IBV_TRANSPORT_UNSPECIFIED: return "unspecified";
+ case IBV_TRANSPORT_SLINGSHOT: return "Slingshot";
default: return "invalid transport";
}
}
@@ -173,6 +174,7 @@ static const char *gid_type_str(enum ibv_gid_type_sysfs type)
case IBV_GID_TYPE_SYSFS_ROCE_V2: return "RoCE v2";
case IBV_GID_TYPE_SYSFS_UET_UDP: return "UET UDP";
case IBV_GID_TYPE_SYSFS_UET_IP: return "UET IP";
+ case IBV_GID_TYPE_SYSFS_SLINGSHOT_UFH: return "SLINGSHOT UFH";
default: return "Invalid gid type";
}
}
diff --git a/libibverbs/examples/ru_cxi_launch.h b/libibverbs/examples/ru_cxi_launch.h
new file mode 100644
index 000000000000..ba87a6cd506d
--- /dev/null
+++ b/libibverbs/examples/ru_cxi_launch.h
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright 2026 Hewlett Packard Enterprise Development LP */
+
+/*
+ * Slingshot (CXI) devices need a service and job grant that only root can
+ * create. cxi_launcher creates them and runs a command under the grant. A
+ * program that finds no grant calls ru_cxi_relaunch() to run itself again
+ * under the launcher; the second run finds UET_JOB_FD and carries on.
+ */
+
+#ifndef RU_CXI_LAUNCH_H
+#define RU_CXI_LAUNCH_H
+
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifndef CXI_LAUNCHER_BINDIR
+#define CXI_LAUNCHER_BINDIR "/usr/bin"
+#endif
+
+#define RU_CXI_MAX_ARGS 256
+
+/* Returns 0 if already running under a grant, -1 on error; else never returns. */
+static inline int ru_cxi_relaunch(const char *devname, uint32_t job_id, int port, int gidx,
+ uint32_t max_addr_entries)
+{
+ char exe[PATH_MAX], launcher[PATH_MAX + 16], cmdline[16384];
+ const char *args[RU_CXI_MAX_ARGS + 16];
+ char idbuf[16], portbuf[16], gidbuf[16], addrbuf[16];
+ ssize_t len, total;
+ size_t n = 0, i;
+ int fd;
+
+ if (getenv("UET_JOB_FD"))
+ return 0;
+ if (geteuid() != 0) {
+ fprintf(stderr,
+ "Slingshot jobs are set up by cxi_launcher, which must run as root; use sudo\n");
+ return -1;
+ }
+
+ len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
+ if (len < 0 || (size_t)len == sizeof(exe) - 1) {
+ if (len >= 0)
+ errno = ENAMETOOLONG;
+ perror("readlink /proc/self/exe");
+ return -1;
+ }
+ exe[len] = 0;
+
+ len = snprintf(launcher, sizeof(launcher), "%s/cxi_launcher", CXI_LAUNCHER_BINDIR);
+ if (len < 0 || (size_t)len >= sizeof(launcher)) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ fd = open("/proc/self/cmdline", O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ perror("open /proc/self/cmdline");
+ return -1;
+ }
+ total = 0;
+ while ((len = read(fd, cmdline + total, sizeof(cmdline) - 1 - total)) > 0)
+ total += len;
+ if ((size_t)total == sizeof(cmdline) - 1) {
+ char extra;
+
+ len = read(fd, &extra, sizeof(extra));
+ if (len > 0) {
+ close(fd);
+ errno = E2BIG;
+ fprintf(stderr, "command line exceeds launcher capacity\n");
+ return -1;
+ }
+ }
+ close(fd);
+ if (len < 0 || total <= 0) {
+ fprintf(stderr, "couldn't read the command line\n");
+ return -1;
+ }
+ if (cmdline[total - 1] != '\0') {
+ errno = E2BIG;
+ return -1;
+ }
+ cmdline[total] = 0;
+
+ snprintf(idbuf, sizeof(idbuf), "%u", job_id);
+ args[n++] = launcher;
+ args[n++] = "-d";
+ args[n++] = devname;
+ args[n++] = "--vni";
+ args[n++] = idbuf;
+ if (port > 0) {
+ snprintf(portbuf, sizeof(portbuf), "%d", port);
+ args[n++] = "-i";
+ args[n++] = portbuf;
+ }
+ if (gidx >= 0) {
+ snprintf(gidbuf, sizeof(gidbuf), "%d", gidx);
+ args[n++] = "-g";
+ args[n++] = gidbuf;
+ }
+ if (max_addr_entries) {
+ snprintf(addrbuf, sizeof(addrbuf), "%u", max_addr_entries);
+ args[n++] = "--max-addr-entries";
+ args[n++] = addrbuf;
+ }
+ /* Run as the sudo caller; a plain root login runs the job as root. */
+ if (!getenv("SUDO_UID")) {
+ args[n++] = "--uid";
+ args[n++] = "0";
+ }
+ args[n++] = "--";
+ args[n++] = exe;
+ /* Skip argv[0] of the original command line. */
+ i = strlen(cmdline) + 1;
+ while (i < (size_t)total && n < RU_CXI_MAX_ARGS) {
+ args[n++] = cmdline + i;
+ i += strlen(cmdline + i) + 1;
+ }
+ if (i < (size_t)total) {
+ fprintf(stderr, "too many arguments\n");
+ return -1;
+ }
+ args[n] = NULL;
+
+ execv(launcher, (char *const *)args);
+ fprintf(stderr, "couldn't run %s: %s\n", launcher, strerror(errno));
+ return -1;
+}
+
+#endif
diff --git a/libibverbs/examples/ru_pingpong.c b/libibverbs/examples/ru_pingpong.c
index 21cc068f2f5b..21a467715a0e 100644
--- a/libibverbs/examples/ru_pingpong.c
+++ b/libibverbs/examples/ru_pingpong.c
@@ -51,8 +51,14 @@
#include <time.h>
#include <inttypes.h>
#include <endian.h>
+#include <stdbool.h>

#include "pingpong.h"
+#ifdef HAVE_CXIVERBS
+#include <infiniband/cxidv.h>
+
+#include "ru_cxi_launch.h"
+#endif

#include <ccan/minmax.h>

@@ -92,6 +98,11 @@ struct pingpong_context {
union ibv_gid gid;
struct ibv_comp_channel *channel;
struct ibv_pd *pd;
+#ifdef HAVE_CXIVERBS
+ struct cxidv_lni *cxi_lni;
+ uint32_t cxi_svc_id;
+#endif
+ uint32_t job_id;
struct ibv_mr *mr;
struct ibv_job *job;
struct ibv_job_key *job_key;
@@ -439,13 +450,10 @@ static int pp_check_dev_caps(struct ibv_context *context)
return -1;
}

- /* The scatter/gather buffer array is sized at PP_MAX_SGE; make sure
- * the device can actually accept that many SGEs per WR.
- */
- if (attr.orig_attr.max_sge < PP_MAX_SGE) {
+ if (use_sge > attr.orig_attr.max_sge) {
fprintf(stderr,
- "PP_MAX_SGE (%d) exceeds device max_sge (%d)\n",
- PP_MAX_SGE, attr.orig_attr.max_sge);
+ "Requested SGEs (%d) exceed device max_sge (%d)\n",
+ use_sge, attr.orig_attr.max_sge);
return -1;
}

@@ -510,7 +518,39 @@ static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
ctx->channel = NULL;
}

- ctx->pd = ibv_alloc_pd(ctx->context);
+ ctx->job_id = DEFAULT_JOB_ID;
+ if (getenv("UET_JOB_ID"))
+ ctx->job_id = strtoul(getenv("UET_JOB_ID"), NULL, 0);
+#ifdef HAVE_CXIVERBS
+ if (ib_dev->transport_type == IBV_TRANSPORT_SLINGSHOT) {
+ const char *service = getenv("UET_SERVICE_ID");
+ uint32_t pid;
+ int ret;
+
+ if (!service) {
+ fprintf(stderr, "No service granted; run under cxi_launcher\n");
+ goto clean_comp_channel;
+ }
+ ctx->cxi_svc_id = strtoul(service, NULL, 0);
+ ret = cxidv_alloc_lni(ctx->context, ctx->cxi_svc_id, &ctx->cxi_lni);
+ if (ret) {
+ fprintf(stderr, "Couldn't allocate LNI: %s\n", strerror(ret));
+ goto clean_comp_channel;
+ }
+ ctx->pd = cxidv_alloc_pd(ctx->cxi_lni);
+ if (!ctx->pd)
+ goto clean_comp_channel;
+ ret = cxidv_alloc_pid(ctx->pd, 0, &pid);
+ if (ret) {
+ fprintf(stderr, "Couldn't bind PD PID: %s\n", strerror(ret));
+ goto clean_pd;
+ }
+ pid_on_fep = pid;
+ } else
+#endif
+ {
+ ctx->pd = ibv_alloc_pd(ctx->context);
+ }
if (!ctx->pd) {
fprintf(stderr, "Couldn't allocate PD\n");
goto clean_comp_channel;
@@ -522,13 +562,20 @@ static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
IBV_JOB_ATTR_MAX_ADDR_ENTRIES |
IBV_JOB_ATTR_PORT_NUM |
IBV_JOB_ATTR_SGID_INDEX),
- .id = DEFAULT_JOB_ID,
+ .id = ctx->job_id,
.max_addr_entries = DEFAULT_ADDR_ENTRIES,
.port_num = port,
.sgid_index = gidx,
};

- ctx->job = ibv_alloc_job(ctx->context, &job_attr, NULL);
+ if (getenv("UET_JOB_FD")) {
+ int fd = strtol(getenv("UET_JOB_FD"), NULL, 0);
+
+ if (ibv_import_job(ctx->context, fd, &ctx->job))
+ ctx->job = NULL;
+ } else {
+ ctx->job = ibv_alloc_job(ctx->context, &job_attr, NULL);
+ }
if (!ctx->job) {
fprintf(stderr, "Couldn't allocate job\n");
goto clean_pd;
@@ -692,6 +739,10 @@ clean_pd:
ibv_dealloc_pd(ctx->pd);

clean_comp_channel:
+#ifdef HAVE_CXIVERBS
+ if (ctx->cxi_lni)
+ cxidv_destroy_lni(ctx->cxi_lni);
+#endif
if (ctx->channel)
ibv_destroy_comp_channel(ctx->channel);

@@ -709,6 +760,8 @@ clean_ctx:

static int pp_close_ctx(struct pingpong_context *ctx)
{
+ int ret = 0;
+
if (ibv_destroy_qp(ctx->qp)) {
fprintf(stderr, "Couldn't destroy QP\n");
return 1;
@@ -747,8 +800,16 @@ static int pp_close_ctx(struct pingpong_context *ctx)

if (ibv_dealloc_pd(ctx->pd)) {
fprintf(stderr, "Couldn't deallocate PD\n");
- return 1;
+ ret = 1;
}
+#ifdef HAVE_CXIVERBS
+ if (ctx->cxi_lni && cxidv_destroy_lni(ctx->cxi_lni)) {
+ fprintf(stderr, "Couldn't destroy LNI\n");
+ ret = 1;
+ }
+#endif
+ if (ret)
+ return ret;

if (ctx->channel) {
if (ibv_destroy_comp_channel(ctx->channel)) {
@@ -1044,6 +1105,8 @@ static void usage(const char *argv0)
printf(" -p, --port <port> listen on/connect to port <port> (default 18515)\n");
printf(" -d, --ib-dev <dev> use IB device <dev> (default first device found)\n");
printf(" -i, --ib-port <port> use port <port> of IB device (default 1)\n");
+ printf(" -j, --job-id <id> JobID (Slingshot VNI) for this side (default %d)\n",
+ DEFAULT_JOB_ID);
printf(" -s, --size <size> size of message to exchange (default 4096)\n");
printf(" -m, --mtu <size> path MTU (default 1024, same on both sides)\n");
printf(" -r, --rx-depth <dep> number of receives to post at a time (default 500)\n");
@@ -1099,6 +1162,7 @@ int main(int argc, char *argv[])
static struct option long_options[] = {
{ .name = "port", .has_arg = 1, .val = 'p' },
{ .name = "ib-dev", .has_arg = 1, .val = 'd' },
+ { .name = "job-id", .has_arg = 1, .val = 'j' },
{ .name = "ib-port", .has_arg = 1, .val = 'i' },
{ .name = "size", .has_arg = 1, .val = 's' },
{ .name = "mtu", .has_arg = 1, .val = 'm' },
@@ -1117,7 +1181,7 @@ int main(int argc, char *argv[])
{}
};

- c = getopt_long(argc, argv, "p:d:i:s:m:r:n:eg:cNQI:S:L",
+ c = getopt_long(argc, argv, "p:d:i:j:s:m:r:n:eg:cNQI:S:L",
long_options, NULL);

if (c == -1)
@@ -1163,6 +1227,9 @@ int main(int argc, char *argv[])
case 'g':
gidx = strtol(optarg, NULL, 0);
break;
+ case 'j':
+ setenv("UET_JOB_ID", optarg, 1);
+ break;
case 'c':
validate_buf = 1;
break;
@@ -1245,6 +1312,19 @@ int main(int argc, char *argv[])
}
}

+#ifdef HAVE_CXIVERBS
+ if (ib_dev->transport_type == IBV_TRANSPORT_SLINGSHOT) {
+ const char *job = getenv("UET_JOB_ID");
+
+ if (ru_cxi_relaunch(ibv_get_device_name(ib_dev),
+ job ? strtoul(job, NULL, 0) : DEFAULT_JOB_ID,
+ ib_port, gidx, 0)) {
+ ibv_free_device_list(dev_list);
+ return 1;
+ }
+ }
+#endif
+
ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, gidx, use_event,
pid_on_fep, resource_index);
if (!ctx)
@@ -1289,8 +1369,11 @@ int main(int argc, char *argv[])
rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, 0,
&my_dest, gidx);

- if (!rem_dest)
+ if (!rem_dest) {
+ pp_close_ctx(ctx);
+ ibv_free_device_list(dev_list);
return 1;
+ }

inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof(gid));
printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n",
@@ -1298,8 +1381,12 @@ int main(int argc, char *argv[])

if (servername) {
if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, 0,
- rem_dest, gidx))
+ rem_dest, gidx)) {
+ pp_close_ctx(ctx);
+ ibv_free_device_list(dev_list);
+ free(rem_dest);
return 1;
+ }
}

ctx->pending = PINGPONG_RECV_WRID;
@@ -1408,11 +1495,22 @@ int main(int argc, char *argv[])
iters, usec / 1000000., usec / iters);

if ((!servername) && (validate_buf)) {
+ int invalid = 0;
+
for (int i = 0; i < size; i += page_size) {
- if (ctx->buf[i] != i / page_size % sizeof(char))
+ if (ctx->buf[i] != i / page_size % sizeof(char)) {
printf("invalid data in page %d\n",
i / page_size);
+ invalid = 1;
+ }
+ }
+ if (invalid) {
+ pp_close_ctx(ctx);
+ ibv_free_device_list(dev_list);
+ free(rem_dest);
+ return 1;
}
+ printf("validate: buffer verified\n");
}
}

diff --git a/libibverbs/examples/ru_rma.c b/libibverbs/examples/ru_rma.c
index ba3f3d1ea198..bd78d9383dbc 100644
--- a/libibverbs/examples/ru_rma.c
+++ b/libibverbs/examples/ru_rma.c
@@ -52,8 +52,14 @@
#include <time.h>
#include <inttypes.h>
#include <endian.h>
+#include <sys/random.h>

#include "pingpong.h"
+#ifdef HAVE_CXIVERBS
+#include <infiniband/cxidv.h>
+
+#include "ru_cxi_launch.h"
+#endif

#include <ccan/minmax.h>

@@ -151,6 +157,7 @@ struct ru_cfg {
uint64_t imm_data64;
int use_event;
int validate_buf;
+ bool mtu_set;
enum ibv_mtu mtu;
};

@@ -162,6 +169,10 @@ struct ru_exchange_info {
};

struct ru_context {
+#ifdef HAVE_CXIVERBS
+ struct cxidv_lni *cxi_lni;
+ uint32_t cxi_svc_id;
+#endif
struct ru_cfg cfg;
struct ibv_job *job;
struct ibv_job_key *job_key;
@@ -243,6 +254,10 @@ static void ru_free_res(struct ru_context *ctx)
ibv_destroy_qp(ctx->qp);
ctx->qp = NULL;
}
+ if (ctx->ah) {
+ ibv_destroy_ah(&ctx->ah->ah_base);
+ ctx->ah = NULL;
+ }

if (ctx->cq) {
ibv_destroy_cq(ctx->cq);
@@ -286,6 +301,15 @@ static void ru_free_res(struct ru_context *ctx)
ibv_dealloc_pd(ctx->pd);
ctx->pd = NULL;
}
+#ifdef HAVE_CXIVERBS
+ if (ctx->cxi_lni) {
+ int ret = cxidv_destroy_lni(ctx->cxi_lni);
+
+ if (ret)
+ RU_ERR("Couldn't destroy LNI: %s", strerror(ret));
+ ctx->cxi_lni = NULL;
+ }
+#endif

if (ctx->channel) {
ibv_destroy_comp_channel(ctx->channel);
@@ -338,6 +362,8 @@ static int ru_init_cfg(int argc, char *argv[], struct ru_context *ctx)
ctx->cfg.do_rma_ex = false;
ctx->cfg.do_rma_ex64 = true; /* default to rma_ex64 */
ctx->cfg.job_id = RU_DEFAULT_JOB_ID;
+ if (getenv("UET_JOB_ID"))
+ ctx->cfg.job_id = strtoul(getenv("UET_JOB_ID"), NULL, 0);

while (1) {
int c;
@@ -402,6 +428,7 @@ static int ru_init_cfg(int argc, char *argv[], struct ru_context *ctx)
RU_USAGE(argv[0]);
return RU_ERR_RC;
}
+ ctx->cfg.mtu_set = true;
break;
case 'r':
ctx->cfg.rx_depth = strtoul(optarg, NULL, 0);
@@ -540,12 +567,9 @@ static int ru_check_dev_caps(struct ru_context *ctx)
return RU_ERR_RC;
}

- /* the local SGE array is sized at RU_MAX_SGE; the device must accept
- * that many SGEs per WR.
- */
- if (attr.orig_attr.max_sge < RU_MAX_SGE) {
- RU_ERR("RU_MAX_SGE (%d) exceeds device max_sge (%d)",
- RU_MAX_SGE, attr.orig_attr.max_sge);
+ if (ctx->cfg.sge > attr.orig_attr.max_sge) {
+ RU_ERR("Requested SGEs (%d) exceed device max_sge (%d)",
+ ctx->cfg.sge, attr.orig_attr.max_sge);
return RU_ERR_RC;
}

@@ -574,7 +598,7 @@ static int ru_init_ctx(struct ru_context *ctx)
ib_dev = *dev_list;
if (!ib_dev) {
RU_ERR("No IB devices found");
- return RU_ERR_RC;
+ goto err_free_devices;
}
} else {
int i;
@@ -588,16 +612,24 @@ static int ru_init_ctx(struct ru_context *ctx)
ib_dev = dev_list[i];
if (!ib_dev) {
RU_ERR("IB device %s not found", ctx->cfg.ib_devname);
- return RU_ERR_RC;
+ goto err_free_devices;
}
}

+#ifdef HAVE_CXIVERBS
+ if (ib_dev->transport_type == IBV_TRANSPORT_SLINGSHOT &&
+ ru_cxi_relaunch(ibv_get_device_name(ib_dev), ctx->cfg.job_id,
+ ctx->cfg.ib_port, ctx->cfg.gidx,
+ ctx->cfg.addr_table ? RU_ADDR_ENTRIES : 0))
+ goto err_free_devices;
+#endif
+
page_size = sysconf(_SC_PAGESIZE);

ctx->buf = memalign(page_size, ctx->cfg.msg_size);
if (!ctx->buf) {
RU_ERR("Couldn't allocate buffer");
- return RU_ERR_RC;
+ goto err_free_devices;
}

if (ctx->cfg.client)
@@ -636,8 +668,48 @@ static int ru_init_ctx(struct ru_context *ctx)
}

memcpy(&ctx->src_id, &ctx->gid.raw[12], sizeof(ctx->src_id));
+ if (ctx->context->device->transport_type == IBV_TRANSPORT_SLINGSHOT &&
+ (ctx->cfg.write32 || ctx->cfg.read32) && !ctx->cfg.user_rkey) {
+ uint32_t key;
+
+ if (getrandom(&key, sizeof(key), 0) != sizeof(key)) {
+ RU_PRINT_ERRNO("Couldn't generate narrow remote key");
+ goto err_exit;
+ }
+ ctx->cfg.user_rkey = true;
+ ctx->cfg.user_rkey_val = key | (1U << 31);
+ }
+
+#ifdef HAVE_CXIVERBS
+ if (ctx->context->device->transport_type == IBV_TRANSPORT_SLINGSHOT) {
+ const char *service = getenv("UET_SERVICE_ID");
+ uint32_t pid;
+ int ret;

- ctx->pd = ibv_alloc_pd(ctx->context);
+ if (!service) {
+ RU_ERR("No service granted; run under cxi_launcher");
+ goto err_exit;
+ }
+ ctx->cxi_svc_id = strtoul(service, NULL, 0);
+ ret = cxidv_alloc_lni(ctx->context, ctx->cxi_svc_id, &ctx->cxi_lni);
+ if (ret) {
+ RU_ERR("Couldn't allocate LNI: %s", strerror(ret));
+ goto err_exit;
+ }
+ ctx->pd = cxidv_alloc_pd(ctx->cxi_lni);
+ if (!ctx->pd)
+ goto err_exit;
+ ret = cxidv_alloc_pid(ctx->pd, ctx->cfg.absolute ? CXIDV_PID_ABSOLUTE : 0, &pid);
+ if (ret) {
+ RU_ERR("Couldn't bind PD PID: %s", strerror(ret));
+ goto err_exit;
+ }
+ ctx->cfg.pid_on_fep = pid;
+ } else
+#endif
+ {
+ ctx->pd = ibv_alloc_pd(ctx->context);
+ }
if (!ctx->pd) {
RU_PRINT_ERRNO("Couldn't allocate protection domain");
goto err_exit;
@@ -654,9 +726,16 @@ static int ru_init_ctx(struct ru_context *ctx)
.sgid_index = ctx->cfg.gidx,
};

- ctx->job = ibv_alloc_job(ctx->context, &job_attr, NULL);
+ if (getenv("UET_JOB_FD")) {
+ int fd = strtol(getenv("UET_JOB_FD"), NULL, 0);
+
+ if (ibv_import_job(ctx->context, fd, &ctx->job))
+ ctx->job = NULL;
+ } else {
+ ctx->job = ibv_alloc_job(ctx->context, &job_attr, NULL);
+ }
if (!ctx->job) {
- RU_ERR("Couldn't allocate job");
+ RU_PRINT_ERRNO("Couldn't allocate job");
goto err_exit;
}

@@ -816,7 +895,11 @@ static int ru_init_ctx(struct ru_context *ctx)
memset(&qp_attr, 0, sizeof(struct ibv_qp_attr));
qp_attr.path_mtu = ctx->cfg.mtu;
qp_init_attr_ex.qp_attr = &qp_attr;
- qp_init_attr_ex.qp_attr_mask = IBV_QP_PATH_MTU;
+ qp_init_attr_ex.qp_attr_mask = ctx->cfg.mtu_set ? IBV_QP_PATH_MTU : 0;
+ if (ctx->context->device->transport_type == IBV_TRANSPORT_SLINGSHOT) {
+ qp_attr.port_num = ctx->cfg.ib_port;
+ qp_init_attr_ex.qp_attr_mask |= IBV_QP_PORT;
+ }

memset(&semantics, 0, sizeof(struct ibv_qp_semantics));

@@ -893,12 +976,15 @@ static int ru_init_ctx(struct ru_context *ctx)
}

ctx->mr_attached = true;
+ ibv_free_device_list(dev_list);

/* the RU QP is created directly in RTS (no INIT/RTR modify) */
return RU_SUCCESS_RC;

err_exit:
ru_free_res(ctx);
+err_free_devices:
+ ibv_free_device_list(dev_list);
return RU_ERR_RC;
}


--
2.56.0