The Versity copyright line names the project, not an individual.
The personal name stays in Signed-off-by. No functional change.
Signed-off-by: Jihyeon Gim <potatogim@potatogim.net>
The Versity copyright line has no corporate suffix, so these
notices should not add one either. No functional change.
Signed-off-by: Jihyeon Gim <potatogim@potatogim.net>
The host verbs shim and the RC server C ABI were written for the
gateway. They use the gateway Apache-2.0 header and carry a
copyright notice for that work. Notices on the hipObject ports
are unchanged.
Signed-off-by: Jihyeon Gim <potatogim@potatogim.net>
Make an explicit RC device selection override any GID hint,
matching the --rc-device contract. A stale hint should not
prevent a named HCA from starting.
Query the selected port before allocating the protection domain and fail initialization when that query fails. Continuing with a zero LID advertises an invalid endpoint on InfiniBand and turns a clear startup error into a later RDMA data-plane failure.
select_gid encodes a RoCE preference order: skip zero and link-local
entries, prefer a RoCEv2 non-IPv4-mapped GID, fall back to IPv4-mapped
v2 and then v1. That order has nothing to pick on a native InfiniBand
port. The only populated entry is index 0, the port GID formed from the
subnet prefix and the port GUID, and it is link-local by construction
(fe80::/10), so the loop discards it and the session fails with "no
usable GID found ... set VGWRDMA_GID_INDEX", even though index 0 is the
one and only correct choice. Every IB user has to hard-code
VGWRDMA_GID_INDEX=0.
Check port_attr.link_layer, which ibv_query_port already returns here,
and take index 0 on IBV_LINK_LAYER_INFINIBAND before the RoCE scan.
RoCE ports are unaffected. Reword the failure message so it no longer
tells IB users to look for a "RoCE GID index", and update the env var
documentation in cuobjclient.
Verified on a ConnectX-6 native IB port (GID table: index 0 =
fe80::…, 1-3 zero): the host client now auto-selects index 0 and
PUT/GET complete against a hipobj/cuObject gateway without the env var;
unpatched it fails at session init with the message above.
The hipobj-rc-v2 server was written against RoCEv2, where the GRH
carries the whole route and the LID in the address handle is unused.
modifyQpToRtr therefore hard-coded ah_attr.dlid = 0, the PREPARE
handler dropped the LID the client token carries, and encodeReplyToken
never filled in our own LID. On an InfiniBand link layer the fabric
switches on the DLID, so every RC session fell over at the data phase:
the client's RDMA write failed with a transport retry exceeded or a
remote invalid request as soon as the QP pair left RTR.
Carry the LID end to end:
- DeviceHandle gains localLid, read from ibv_query_port at init.
- The PREPARE handler stashes the client LID from the token next to
the peer GID; the loopback fallback uses our own LID.
- READY passes that LID into the RTR transition, and modifyQpToRtr
sets ah_attr.dlid from it. is_global stays set: a GRH is valid on
IB and RoCE still needs it, and on RoCE the callers keep passing 0.
- encodeReplyToken fills token.lid so the client can address us.
The 44-byte token has always had the lid field; no wire change.
Verified on a native InfiniBand fabric (ConnectX-6, 200G HDR, SM lid 8)
with the gateway on a Rocky 8.10 storage node using inbox verbs and an
RC client that consumes the reply token LID: PUT and GET complete with
the DLID set, and fail exactly as described with the previous dlid = 0.
The hipobj-rc-v2 server chooses its HCA as "the first verbs device
that opens", or the first whose GID begins with --rc-gid-hint. Neither
works on a storage node with more than one RDMA adapter. Enumeration
order is not a fabric choice, and the hint compares only the first
four GID bytes: every port's GID 0 is link-local, so an InfiniBand
HCA and a RoCE NIC on the same host both match fe:80:0:0, and IPv4-
mapped RoCE GIDs all match 0:0:0:0.
We hit this on a node with two ConnectX-6 IB ports and two Broadcom
RoCE ports: the gateway silently bound bnxt_re0 (link_layer Ethernet,
LID 0, no path to the clients on the IB fabric) and every RC session
timed out in the data phase with nothing in the log to say why.
Add --rc-device / VGW_RC_DEVICE, plumbed through DeviceOpts.DevName
and rc_device_opts.dev_name, that filters the device list by
ibv_device.name before the GID-hint match. It takes precedence over
the hint; the hint still applies within the named device. The failure
message now names the device that was asked for.
09bbe9c resolved the three inline-only verbs from the ops table of
"the first successfully opened context" and cached the pointers for
every later call, on the assumption that one provider serves the
whole process. That holds on a single-HCA host and nowhere else. On
a storage node with a ConnectX-6 IB adapter and a Broadcom RoCE NIC,
ibv_get_device_list returned bnxt_re0 first, so the RC data plane
bound to mlx5_0 posted its receives and polled its CQ through
libbnxt_re: every session stalled in the data phase, and once a
peer actually reached the QP the gateway died with SIGSEGV inside
libbnxt_re-rdmav34.so (a NULL read at qp+0xc0, the bnxt provider
interpreting an mlx5 QP).
Do what the verbs.h inline wrappers do: route each call through
cq->context->ops / qp->context->ops, so the provider that opened the
object handles it. A missing slot returns ENOSYS instead of jumping
to address zero. No probe device is needed any more, so a host whose
first device fails to open no longer disables the RC data plane.
Found on a native InfiniBand fabric while bringing up the RC data
plane on a multi-HCA node; verified that with per-context dispatch
the same PUT/GET complete (see the follow-up LID fix for the other
half of IB support).
NVIDIA's rolling cuda-rhel9 repository bumped libcuobjserver from `1.2.0` to `2.0.0` and `build/vgwrdma-builder/Dockerfile` installs it unpinned, so `make vgwrdma-docker` broke: `setTelemFlags` gained a second mask and `initRDMAConfigParams` vanished along with the `RDMAConnection` base class that 2.0.0 deletes entirely. Rather than pin the package, this ports the C wrapper and the Go `rdma` package to the new API.
Telemetry now calls `setTelemFlags(flags, 0)`, where 0 reproduces the old behaviour. `Server.InitRDMAConfig` and its C entry point are removed, which drops a method from the exported API of `github.com/versity/versitygw/rdma`; it had no callers, and 2.0.0 only accepts tunables through the four-argument constructor that `NewServer` already uses. The `dlsym` lookups for `startRDMASession` and `closeRDMASession` go too, as dead code: 1.2.0 never exported those symbols either, so the fallback paths were always what ran. `HandleGet` and `HandlePut` now wrap the library's negative return in a `syscall.Errno` so 2.0.0's new `-EPROTO` is legible, and the wrapper compile rule gains `-std=c++17`. No defaults change.
`make vgwrdma-docker` passes and the binary links `libcuobjserver.so.2`, so it requires a 2.x install at runtime. `cuobjtest-gpu` and `cuobjtest-host` are unaffected. The RDMA data path itself is not verified here; that needs Mellanox hardware with DC transport.
A native completion call fires the teardown callback before it
returns, so an outcome recorded after the call is too late: every
successful transfer published as an expiry, and PUT failures and
panics lost their real outcome to the callback's placeholder.
The READY handler now reserves the session record before invoking
any completion call. A reserved record is invisible to the
callback, and the handler publishes the real outcome exactly once
after the result is known. A deferred safety net publishes on
panic unwinds before the unwind finalizer retires the session.
Successful PUTs forward the backend-assigned ETag and version into
the object-created event, and the audit record carries the
transferred byte count as the object size.
A READY whose re-authorization fails now publishes the denial
itself before canceling, instead of letting the cancel publish an
expiry.
The native side keeps the terminal reason on every failure exit:
a verify failure no longer overwrites the wire-failure outcome,
and QP transition or re-arm failures record the wire failure they
return. The unclaimed-teardown classification follows the wire
mapping, so every transfer-level failure the client would see as
502 publishes as the same 502 instead of a diverging per-cause
code.
The metrics bucket tag is documented as absent on synthesized
publications: route parameters come from route matching, which a
synthesized request never runs; the audit log derives the bucket
from the path and stays accurate.
RC sessions that never reach a completion (expired, abandoned, or canceled before READY) currently vanish inside the reaper without any trace on the operational surface. Add a terminal notification callback to the C ABI so the server reports the final outcome of every session exactly once, fired from the reaper with no server lock held.
Expose rc_server_sessions_snapshot, which copies every live session
into fixed rc_session_snapshot records under the map lock and invokes
the callback once per record outside the lock. Each session records a
monotonic creation timestamp, because the prepare/ready deadlines move
as the session progresses and cannot serve as an age reference. The
state byte combines the session state machine value with a
reap-pending marker, so callers can distinguish sessions that are
about to be reaped from healthy ones. Records whose op or target does
not fit the fixed fields are skipped rather than truncated.
The session id only existed as the sessions map key; the session
record itself kept an empty id string, so the terminal reap record
logged an empty id for every expired, cancelled, or destroyed
session. Copy the id into the record at creation time so teardown
logs identify the session they describe.
ibv_poll_cq, ibv_post_send, and ibv_post_recv stopped being
exported library symbols in modern rdma-core: verbs.h ships them
as static inline wrappers that dispatch through
cq->context->ops. dlsym therefore returned null for them and the
loader rejected perfectly usable libraries, failing RC server
init with a bare RC_E_INTERNAL on hosts with rdma-core 61+.
Open the first device briefly, read the three function pointers
from its context ops table, and close it again. The check now
only requires symbols that actually exist in the library, and
the failure mode for an ops-less provider is explicit.
The verbs loader and device enumeration failures returned
RC_E_INTERNAL without any stderr trace, which made a VM or
container without RDMA indistinguishable from a genuine
library problem. Print the failing step so operators can tell
the two apart at startup.
Wire C-side diagnostics (session reap, READY data phase outcome,
init failures) through a sink callback so the gateway can surface
them next to its own logs instead of losing them in stderr noise.
The sink is a plain C function pointer installed once after init
and valid until destroy: the Go side registers a fixed cgo
trampoline (closures cannot cross the boundary), copies the
message immediately per the lifetime contract, and never runs
under the session map lock. Error-level lines keep the existing
stderr output; --debug enables the level-2 diagnostic stream.
Wrap the v2 session core with the server-side C ABI the gateway
binds to: prepare/ready/cancel session calls, staging leases for
GET side-loading, the put-view handoff for PUT commits, session
introspection, and the server lifecycle.
The ABI owns the parts that must be shared across sessions: the
verbs device handle, global and per-principal resource limits,
session accounting with consume-once handles keyed by epoch and
nonce, the completion reference that pins a session from the
READY claim until its finalizer, and the reaper that tears
transport objects down once every reference drains. A background
thread expires sessions past their prepare or execute deadlines
so abandoned sessions cannot pin the limits, and teardown
failures keep the affected verbs objects and device alive rather
than freeing memory the NIC may still reference.
A peer-busy READY rolls the claim back and re-arms the QP
through RESET so the client can retry the same session. The
vgwrdma target now links the archive built from these sources.
Signed-off-by: Jihyeon Gim <potatogim@potatogim.net>
Port the hipObject v2 reliable-connection session core into
cuwrapper/rc: the session table and state machine, the wire
codec for the hipobj-rc-v2 headers, request parsing, the
injectable clock and randomness sources, the transport layer
(QP/CQ lifecycle, RTR/RTS transitions, staging registration),
the data phase (RDMA write with immediate for GET, receive with
immediate for PUT), the RDMA token codec, and the dynamically
loaded ibverbs shim (ibv-core.h plus the dlopen host binding).
The sources are a port of the upstream hipObject v2 core, kept
close to the original so the two trees can be diffed during
review. Nothing links against them yet; a Makefile rule builds
the objects into rdma/librcserver.a for the ABI layer that
follows.
Signed-off-by: Jihyeon Gim <potatogim@potatogim.net>