mirror of
https://github.com/versity/versitygw.git
synced 2026-09-23 16:34:18 +00:00
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>
107 lines
4.1 KiB
C++
107 lines
4.1 KiB
C++
/* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
* Copyright (c) Gluesys Inc. and Jihyeon Gim. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
/* v2 transport: device/qp ownership split and release procedure.
|
|
*
|
|
* DeviceHandle is the shared half (context, protection domain,
|
|
* topology) with a connection reference count; RcConnV2 owns one
|
|
* qp/cq pair. v2 entry points route through these helpers so the
|
|
* registry, capacity accounting, and the retired ring stay
|
|
* consistent. Everything runs under v2::apiLock(). */
|
|
|
|
#pragma once
|
|
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
|
|
#include "ibv-core.h"
|
|
#include "v2-registry.h"
|
|
|
|
namespace hipObj {
|
|
|
|
struct DeviceHandle {
|
|
struct ibv_context* ctx = nullptr;
|
|
struct ibv_pd* pd = nullptr;
|
|
uint8_t portNum = 1;
|
|
int gidIndex = -1;
|
|
union ibv_gid localGid = {};
|
|
std::atomic<uint32_t> connRefs{0};
|
|
};
|
|
|
|
namespace v2 {
|
|
|
|
/* Creates the qp/cq pair on dh. On success conn holds both objects,
|
|
* conn.qpNum is captured, and dh->connRefs was incremented. On
|
|
* failure every partially created object was rolled back (rollback
|
|
* failures are reported via *rollbackFailed so the caller can raise
|
|
* a poisoned tombstone). */
|
|
int createRcConnV2(DeviceHandle* dh, RcConnV2& conn,
|
|
bool* rollbackFailed = nullptr);
|
|
|
|
/* Destroys conn's qp and cq. Reflects per-object success through
|
|
* the out flags; the caller feeds them to commitDestroy(). */
|
|
void destroyRcConnV2(RcConnV2& conn, bool* qpOk, bool* cqOk);
|
|
|
|
/* QP state transitions taking the device topology from dh. The v1
|
|
* signatures (RcConnection&) remain unchanged. */
|
|
int transitionQpToInitV2(DeviceHandle* dh, RcConnV2& conn);
|
|
int transitionQpToRtrV2(DeviceHandle* dh, RcConnV2& conn, uint32_t destQpNum,
|
|
uint16_t destLid, union ibv_gid destGid,
|
|
uint32_t rqPsn);
|
|
int transitionQpToRtsV2(RcConnV2& conn, DeviceHandle* dh, uint32_t sqPsn);
|
|
|
|
/* Drives a QP from any state (including RTS/ERR after a failed
|
|
* transfer) back to INIT. The verbs state table has no direct
|
|
* RTS->INIT edge, so this goes through RESET, which is valid from
|
|
* every state. */
|
|
int rearmQpToInitV2(DeviceHandle* dh, RcConnV2& conn);
|
|
|
|
/* Creates only a qp on an existing cq (conflict-discard retry uses
|
|
* this so the original cq survives). */
|
|
int createRcQpOnly(DeviceHandle* dh, struct ibv_cq* cq, RcConnV2& conn);
|
|
|
|
/* Retires a live qp whose (qpn, psn) was already used by a peer:
|
|
* reserves a fresh ring slot, destroys the old qp, records the
|
|
* tuple, and recreates the qp on the existing cq. On any failure
|
|
* the entry keeps its live qp and reservation (callers surface the
|
|
* error); the busy return means the retired ring is exhausted. */
|
|
int discardAndRecreateQp(ConnId id);
|
|
|
|
/* Decrements dh->connRefs after a successful releaseRcConnV2 and
|
|
* closes ctx/pd when no MR and no connection remain. */
|
|
void releaseDevice(DeviceHandle* dh);
|
|
|
|
/* Full v2 release procedure for one registry entry: claim, reserve
|
|
* a retired slot for a live qp, destroy, commit, record, erase.
|
|
* Returns a hipObj error code (0 = success, busy = deferred,
|
|
* rdma = leftover/poison). */
|
|
int releaseConnection(ConnId id);
|
|
|
|
/* Posts the zero-SGE receive work request (wr_id = kRecvImm). */
|
|
constexpr uint64_t kRecvImm = 0x5245435632494d4dULL; /* "RECV2IMM" */
|
|
int postRecvImm(DeviceHandle* dh, RcConnV2& conn);
|
|
|
|
/* Completion validation for the data phase. A GET consumes one
|
|
* RECV_RDMA_WITH_IMM completion; a PUT consumes one RECV completion
|
|
* carrying the immediate (flags & IBV_WC_WITH_IMM). The immediate
|
|
* carries the session cookie in network order - the byte count
|
|
* travels in the FINAL response instead. */
|
|
enum class WcKind { kGet, kPut };
|
|
|
|
struct WcExpectation {
|
|
WcKind kind;
|
|
uint64_t wrId; /* expected wr_id (kRecvImm for receives) */
|
|
uint32_t cookie; /* expected immediate value (the cookie) */
|
|
};
|
|
|
|
/* Validates one work completion against the expectation; returns
|
|
* false and fills *reason on mismatch. */
|
|
bool validateDataCompletion(const struct ibv_wc& wc,
|
|
const WcExpectation& expect, const char** reason);
|
|
|
|
} // namespace v2
|
|
} // namespace hipObj
|