mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-20 22:27:04 +00:00
rdma-engine: real libibverbs/rdma_cm RDMA READ datapath (proof of plumbing)
The engine backend was a mock: post_read fabricated byte=i%256 and
never touched a wire (the Go sidecar even discarded the engine reply
and re-faked the same pattern). Add a real datapath behind a new
'real-rdma' cargo feature:
- src/rdma_real.rs: RealRdmaContext (connect via rdma_cm, register_memory,
a genuine IBV_WR_RDMA_READ via rdma_post_read, poll_completion,
device_info) + RealResponder (rdma_reg_read REMOTE_READ source that
hands the client {addr,rkey,len}).
- src/bin/rdma_loopback.rs: proof binary. A responder registers a buffer
with a verifiable pattern (REALRDMA magic header, not the mock's i%256);
the client RDMA-READs it and verifies the bytes match.
- REAL_RDMA.md: build/run + design notes.
Verified on a SoftRoCE (rxe) loopback (Linux 6.12.90, rdma_rxe):
1 MiB IBV_WR_RDMA_READ completes status=Success, dest head 'REALRDMA',
1048576 bytes match -> REAL-RDMA-READ-SUCCESS. (rxe on a 2-vCPU VM is a
correctness proof, not a benchmark.)
vendor/rdma-sys: rdma-sys 0.3.0 with bindgen bumped to 0.69.4 (the
crates.io 0.59.2 pin cannot parse rdma-core 56 headers); redirected via
[patch.crates-io]. Temporary workaround; see REAL_RDMA.md.
Phase-1 proof of plumbing only. A demonstrable zero-copy read of real
volume data still needs a needle-backed RDMA target in the volume
server, a control-plane handshake, an IPC-contract change, and mount
wiring (multi-week; deferred).
This commit is contained in:
+160
-7
@@ -161,6 +161,29 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.69.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
|
||||
dependencies = [
|
||||
"bitflags 2.9.2",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
@@ -230,6 +253,15 @@ dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.1"
|
||||
@@ -248,7 +280,7 @@ dependencies = [
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -278,6 +310,17 @@ dependencies = [
|
||||
"half",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.45"
|
||||
@@ -530,6 +573,12 @@ version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.6.0"
|
||||
@@ -561,6 +610,15 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
@@ -655,6 +713,12 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.175"
|
||||
@@ -677,6 +741,12 @@ version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.4"
|
||||
@@ -723,6 +793,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
@@ -910,6 +989,12 @@ version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.7"
|
||||
@@ -947,6 +1032,16 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.100"
|
||||
@@ -1073,6 +1168,7 @@ dependencies = [
|
||||
"nix",
|
||||
"parking_lot",
|
||||
"proptest",
|
||||
"rdma-sys",
|
||||
"rmp-serde",
|
||||
"serde",
|
||||
"tempfile",
|
||||
@@ -1084,6 +1180,17 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdma-sys"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"libc",
|
||||
"memoffset",
|
||||
"paste",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.17"
|
||||
@@ -1171,6 +1278,25 @@ version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags 2.9.2",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.8"
|
||||
@@ -1180,7 +1306,7 @@ dependencies = [
|
||||
"bitflags 2.9.2",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"linux-raw-sys 0.9.4",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
@@ -1338,7 +1464,7 @@ dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"rustix 1.0.8",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@@ -1671,6 +1797,18 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
|
||||
dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"once_cell",
|
||||
"rustix 0.38.44",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
@@ -1688,7 +1826,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-link 0.1.3",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
@@ -1721,13 +1859,19 @@ version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1736,7 +1880,7 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1766,6 +1910,15 @@ dependencies = [
|
||||
"windows-targets 0.53.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
@@ -1788,7 +1941,7 @@ version = "0.53.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.3",
|
||||
"windows_aarch64_gnullvm 0.53.0",
|
||||
"windows_aarch64_msvc 0.53.0",
|
||||
"windows_i686_gnu 0.53.0",
|
||||
|
||||
@@ -10,6 +10,13 @@ license = "Apache-2.0"
|
||||
name = "rdma-engine-server"
|
||||
path = "src/main.rs"
|
||||
|
||||
# Phase-1 proof: a real IBV_WR_RDMA_READ over SoftRoCE loopback (requires Linux +
|
||||
# libibverbs/librdmacm). Build with: cargo build --features real-rdma --bin rdma-loopback
|
||||
[[bin]]
|
||||
name = "rdma-loopback"
|
||||
path = "src/bin/rdma_loopback.rs"
|
||||
required-features = ["real-rdma"]
|
||||
|
||||
[lib]
|
||||
name = "rdma_engine"
|
||||
path = "src/lib.rs"
|
||||
@@ -48,6 +55,10 @@ parking_lot = "0.12" # Fast mutexes
|
||||
nix = { version = "0.27", features = ["mman"] } # Unix domain sockets and system calls
|
||||
async-trait = "0.1" # Async traits
|
||||
|
||||
# Real RDMA via libibverbs + librdmacm (raw FFI). Optional, Linux-only; pulled in
|
||||
# by the `real-rdma` feature. Used by src/rdma_real.rs (RealRdmaContext).
|
||||
rdma-sys = { version = "0.3", optional = true }
|
||||
|
||||
# Configuration
|
||||
clap = { version = "4.0", features = ["derive"] }
|
||||
config = "0.13"
|
||||
@@ -61,6 +72,7 @@ tempfile = "3.0"
|
||||
default = ["mock-ucx"]
|
||||
mock-ucx = []
|
||||
real-ucx = [] # UCX integration for production RDMA
|
||||
real-rdma = ["dep:rdma-sys"] # real libibverbs/rdma_cm datapath (SoftRoCE/real NIC)
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
@@ -72,3 +84,6 @@ panic = "abort"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["real-rdma"]
|
||||
|
||||
[patch.crates-io]
|
||||
rdma-sys = { path = "vendor/rdma-sys" }
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# Real RDMA datapath (`real-rdma` feature) — proof of plumbing
|
||||
|
||||
The engine's default backend is a **mock** (`src/rdma.rs` `MockRdmaContext`): its
|
||||
`post_read` fabricates `byte = i % 256` and never touches a wire (the Go sidecar
|
||||
in `../pkg/rdma/client.go` even discards the engine's buffer and re-fakes the
|
||||
same pattern). This module replaces that with a **real** libibverbs / `rdma_cm`
|
||||
datapath, validated over SoftRoCE (rxe).
|
||||
|
||||
## What's here
|
||||
|
||||
- `src/rdma_real.rs`
|
||||
- `RealRdmaContext` — the real client backend: `connect` (via `rdma_cm` /
|
||||
`rdma_create_ep`), `register_memory`, `post_read` (a genuine
|
||||
`IBV_WR_RDMA_READ` via `rdma_post_read`), `poll_completion`, `device_info`.
|
||||
- `RealResponder` — a throwaway loopback target: registers a buffer for
|
||||
`REMOTE_READ` (`rdma_reg_read`) and hands the client its `{addr, rkey, len}`.
|
||||
- `src/bin/rdma_loopback.rs` — the proof: a responder registers a buffer with a
|
||||
verifiable pattern (a `REALRDMA` magic header — deliberately **not** the mock's
|
||||
`i%256`), the client RDMA-READs it, and asserts the bytes match.
|
||||
|
||||
Connection setup and QP state transitions use `rdma_cm` (much simpler than a
|
||||
manual GID/QPN/LID handshake for RoCEv2 addressing).
|
||||
|
||||
## Build & run (Linux + SoftRoCE only)
|
||||
|
||||
Requires `libibverbs-dev librdmacm-dev ibverbs-providers ibverbs-utils
|
||||
rdma-core clang libclang-dev`, and a SoftRoCE link:
|
||||
|
||||
```sh
|
||||
sudo modprobe rdma_rxe rdma_ucm
|
||||
sudo rdma link add rxe0 type rxe netdev eth0 # eth0 = your primary netdev
|
||||
ibv_rc_pingpong -d rxe0 -g 1 # sanity-check the fabric
|
||||
|
||||
cargo build --features real-rdma --bin rdma-loopback
|
||||
sudo ./target/debug/rdma-loopback <rxe_ip> 7471 1048576 # rxe_ip = eth0's IP
|
||||
# => REAL-RDMA-READ-SUCCESS, dest head "REALRDMA", bytes match
|
||||
```
|
||||
|
||||
(rxe on a low-vCPU VM is a **correctness** proof, not a representative benchmark.)
|
||||
|
||||
## Why `vendor/rdma-sys`
|
||||
|
||||
`rdma-sys 0.3.0` (crates.io) pins **bindgen 0.59.2**, which cannot parse the
|
||||
`rdma-core 56` headers (`ib_uverbs_flow_action_esp_encap_union_… is not a valid
|
||||
Ident`). `vendor/rdma-sys` is rdma-sys 0.3.0 with bindgen bumped to 0.69.4 (and
|
||||
the two methods removed in modern bindgen — `rustfmt_bindings` / `size_t_is_usize`
|
||||
— dropped from its `build.rs`); `Cargo.toml` redirects to it via
|
||||
`[patch.crates-io]`. This is a temporary workaround — upstreaming a bindgen bump
|
||||
to rdma-sys, or moving to a maintained bindings crate, is the cleaner long-term
|
||||
fix.
|
||||
|
||||
## Not done (the real RDMA *win* is multi-week)
|
||||
|
||||
This is Phase-1 proof-of-plumbing only. A demonstrable zero-copy read of real
|
||||
volume data still needs: a needle-backed RDMA **target** in the volume server
|
||||
(none exists today), a control-plane handshake to publish `{remote_addr, rkey}`,
|
||||
a breaking IPC-contract change (Rust + Go, in lockstep), mount wiring, and then
|
||||
the zero-copy READ path. See the scoping notes for the phased plan.
|
||||
@@ -0,0 +1,95 @@
|
||||
//! Phase-1 proof: a real `IBV_WR_RDMA_READ` over SoftRoCE (rxe) loopback.
|
||||
//!
|
||||
//! Spawns a [`RealResponder`] that registers a buffer holding a verifiable
|
||||
//! pattern (with a `REALRDMA` magic header — deliberately NOT the mock's `i%256`),
|
||||
//! then a [`RealRdmaContext`] client connects, RDMA-READs the buffer, and asserts
|
||||
//! the bytes match. Proves the engine moves real bytes over a genuine RDMA verb.
|
||||
//!
|
||||
//! rmmod-free run (after SoftRoCE is up):
|
||||
//! cargo run --features real-rdma --bin rdma-loopback -- <rxe_ip> [port] [len]
|
||||
//!
|
||||
//! `<rxe_ip>` must be an IP on the netdev backing the rxe link (e.g. eth0's IP),
|
||||
//! not 127.0.0.1 (rxe is bound to that netdev, not loopback).
|
||||
|
||||
use std::sync::mpsc;
|
||||
use std::time::Instant;
|
||||
|
||||
use rdma_engine::rdma_real::{RealRdmaContext, RealResponder};
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let ip = args.get(1).cloned().unwrap_or_else(|| "127.0.0.1".into());
|
||||
let port: u16 = args.get(2).and_then(|s| s.parse().ok()).unwrap_or(7471);
|
||||
let len: usize = args.get(3).and_then(|s| s.parse().ok()).unwrap_or(1 << 20);
|
||||
|
||||
// A verifiable pattern, distinct from the mock's i%256, with a magic header.
|
||||
let mut src = vec![0u8; len];
|
||||
for (i, b) in src.iter_mut().enumerate() {
|
||||
*b = (i.wrapping_mul(131).wrapping_add(17) & 0xff) as u8;
|
||||
}
|
||||
let magic = b"REALRDMA";
|
||||
src[..magic.len()].copy_from_slice(magic);
|
||||
let expected = src.clone();
|
||||
|
||||
let (ready_tx, ready_rx) = mpsc::channel::<()>();
|
||||
let sip = ip.clone();
|
||||
let server = std::thread::spawn(move || {
|
||||
let mut data = src;
|
||||
if let Err(e) = RealResponder::serve_once(&sip, port, &mut data, move || {
|
||||
let _ = ready_tx.send(());
|
||||
}) {
|
||||
eprintln!("responder error: {e}");
|
||||
}
|
||||
});
|
||||
// Wait until the responder is listening before connecting.
|
||||
let _ = ready_rx.recv();
|
||||
|
||||
let t0 = Instant::now();
|
||||
let (ctx, raddr, rkey, rlen) = match RealRdmaContext::connect(&ip, port) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
eprintln!("client connect failed: {e}");
|
||||
let _ = server.join();
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
println!(
|
||||
"connected: device={:?} remote MR addr=0x{raddr:x} rkey=0x{rkey:x} len={rlen}",
|
||||
ctx.device_info().name
|
||||
);
|
||||
|
||||
let mut dest = vec![0u8; rlen];
|
||||
let (_mrinfo, mr) = ctx.register_memory(&mut dest).expect("register dest");
|
||||
ctx.post_read(&mut dest, mr, raddr, rkey, 1).expect("post_read");
|
||||
let wc = ctx.poll_completion().expect("poll completion");
|
||||
let dt = t0.elapsed();
|
||||
ctx.finish();
|
||||
let _ = server.join();
|
||||
|
||||
let head: String = dest[..16.min(dest.len())]
|
||||
.iter()
|
||||
.map(|b| format!("{b:02x}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
println!(
|
||||
"RDMA READ done: status={:?} byte_len={} dest head: {head} (\"{}\")",
|
||||
wc.status,
|
||||
wc.byte_len,
|
||||
String::from_utf8_lossy(&dest[..magic.len().min(dest.len())])
|
||||
);
|
||||
|
||||
if dest == expected {
|
||||
let mibps = (rlen as f64 / (1024.0 * 1024.0)) / dt.as_secs_f64();
|
||||
println!("VERIFY OK: {rlen} bytes match the responder's registered buffer");
|
||||
println!("({mibps:.1} MiB/s incl. connection setup; rxe on a 2-vCPU VM is a correctness proof, not a benchmark)");
|
||||
println!("REAL-RDMA-READ-SUCCESS");
|
||||
} else {
|
||||
let mismatch = dest
|
||||
.iter()
|
||||
.zip(expected.iter())
|
||||
.position(|(a, b)| a != b)
|
||||
.unwrap_or(0);
|
||||
eprintln!("VERIFY FAILED: first mismatch at byte {mismatch}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,8 @@ use anyhow::Result;
|
||||
|
||||
pub mod ucx;
|
||||
pub mod rdma;
|
||||
#[cfg(feature = "real-rdma")]
|
||||
pub mod rdma_real; // real libibverbs/rdma_cm RDMA datapath (SoftRoCE/real NIC)
|
||||
pub mod ipc;
|
||||
pub mod session;
|
||||
pub mod memory;
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
//! Real RDMA datapath over libibverbs + librdmacm (`rdma_cm`).
|
||||
//!
|
||||
//! Phase-1 proof-of-plumbing: a genuine `IBV_WR_RDMA_READ` (via the librdmacm
|
||||
//! convenience verb `rdma_post_read`) that pulls *real* bytes out of a remote
|
||||
//! peer's registered memory region over SoftRoCE (rxe) — replacing the mock
|
||||
//! engine that fabricated `byte = i % 256` and never touched a wire.
|
||||
//!
|
||||
//! [`RealRdmaContext`] is the client (the engine's real backend: connect /
|
||||
//! register_memory / post_read / poll_completion / device_info); [`RealResponder`]
|
||||
//! is a throwaway loopback target that registers a buffer for `REMOTE_READ` and
|
||||
//! hands the client its `{addr, rkey, len}`. Connection setup and QP state
|
||||
//! transitions are handled by `rdma_cm` (much simpler than a manual GID/QPN/LID
|
||||
//! handshake for RoCEv2). Linux + libibverbs/librdmacm only (`real-rdma` feature).
|
||||
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::ptr::null_mut;
|
||||
|
||||
use rdma_sys::*;
|
||||
|
||||
use crate::error::{RdmaError, RdmaResult};
|
||||
use crate::rdma::{CompletionStatus, MemoryRegion, RdmaDeviceInfo, RdmaOp, WorkCompletion};
|
||||
|
||||
/// Metadata the responder hands the client so it can RDMA-READ the source MR.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
struct RemoteInfo {
|
||||
addr: u64,
|
||||
rkey: u32,
|
||||
len: u32,
|
||||
}
|
||||
|
||||
const META_LEN: usize = std::mem::size_of::<RemoteInfo>();
|
||||
|
||||
fn op_failed(op: &str) -> RdmaError {
|
||||
RdmaError::OperationFailed {
|
||||
operation: format!("{op}: {}", std::io::Error::last_os_error()),
|
||||
status: -1,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn qp_init_attr() -> ibv_qp_init_attr {
|
||||
let mut a: ibv_qp_init_attr = std::mem::zeroed();
|
||||
a.cap.max_send_wr = 8;
|
||||
a.cap.max_recv_wr = 8;
|
||||
a.cap.max_send_sge = 1;
|
||||
a.cap.max_recv_sge = 1;
|
||||
a.sq_sig_all = 1;
|
||||
a
|
||||
}
|
||||
|
||||
// Allow at least one outstanding RDMA READ in each direction.
|
||||
unsafe fn conn_param() -> rdma_conn_param {
|
||||
let mut cp: rdma_conn_param = std::mem::zeroed();
|
||||
cp.responder_resources = 1;
|
||||
cp.initiator_depth = 1;
|
||||
cp.retry_count = 7;
|
||||
cp.rnr_retry_count = 7;
|
||||
cp
|
||||
}
|
||||
|
||||
unsafe fn query_device(id: *mut rdma_cm_id) -> RdmaDeviceInfo {
|
||||
let ctx = (*id).verbs;
|
||||
let mut attr: ibv_device_attr = std::mem::zeroed();
|
||||
let mut name = String::from("unknown");
|
||||
if !ctx.is_null() {
|
||||
ibv_query_device(ctx, &mut attr);
|
||||
let dev = (*ctx).device;
|
||||
if !dev.is_null() {
|
||||
name = CStr::from_ptr((*dev).name.as_ptr())
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
}
|
||||
}
|
||||
RdmaDeviceInfo {
|
||||
name,
|
||||
vendor_id: attr.vendor_id,
|
||||
vendor_part_id: attr.vendor_part_id,
|
||||
hw_ver: attr.hw_ver,
|
||||
max_mr: attr.max_mr as u32,
|
||||
max_qp: attr.max_qp as u32,
|
||||
max_cq: attr.max_cq as u32,
|
||||
max_mr_size: attr.max_mr_size,
|
||||
port_gid: String::new(),
|
||||
port_lid: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Busy-poll a librdmacm completion helper (`rdma_get_send_comp` /
|
||||
/// `rdma_get_recv_comp`) until it returns a completion or an error.
|
||||
unsafe fn wait_comp(
|
||||
f: unsafe fn(*mut rdma_cm_id, *mut ibv_wc) -> c_int,
|
||||
id: *mut rdma_cm_id,
|
||||
what: &str,
|
||||
) -> RdmaResult<ibv_wc> {
|
||||
let mut wc: ibv_wc = std::mem::zeroed();
|
||||
loop {
|
||||
let n = f(id, &mut wc);
|
||||
if n < 0 {
|
||||
return Err(op_failed(what));
|
||||
}
|
||||
if n > 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if wc.status != ibv_wc_status::IBV_WC_SUCCESS {
|
||||
return Err(RdmaError::OperationFailed {
|
||||
operation: format!("{what}: wc status {}", wc.status),
|
||||
status: wc.status as i32,
|
||||
});
|
||||
}
|
||||
Ok(wc)
|
||||
}
|
||||
|
||||
/// The real RDMA client backend.
|
||||
pub struct RealRdmaContext {
|
||||
id: *mut rdma_cm_id,
|
||||
device: RdmaDeviceInfo,
|
||||
}
|
||||
|
||||
impl RealRdmaContext {
|
||||
/// Connect to a responder at `ip:port` and receive the `{addr, rkey, len}`
|
||||
/// of its RDMA-READable source memory region.
|
||||
pub fn connect(ip: &str, port: u16) -> RdmaResult<(Self, u64, u32, usize)> {
|
||||
unsafe {
|
||||
let node = CString::new(ip).map_err(|_| op_failed("bad ip"))?;
|
||||
let svc = CString::new(port.to_string()).unwrap();
|
||||
let mut hints: rdma_addrinfo = std::mem::zeroed();
|
||||
hints.ai_port_space = rdma_port_space::RDMA_PS_TCP as c_int;
|
||||
let mut res: *mut rdma_addrinfo = null_mut();
|
||||
if rdma_getaddrinfo(node.as_ptr(), svc.as_ptr(), &hints, &mut res) != 0 {
|
||||
return Err(op_failed("rdma_getaddrinfo(client)"));
|
||||
}
|
||||
let mut attr = qp_init_attr();
|
||||
let mut id: *mut rdma_cm_id = null_mut();
|
||||
let r = rdma_create_ep(&mut id, res, null_mut(), &mut attr);
|
||||
rdma_freeaddrinfo(res);
|
||||
if r != 0 {
|
||||
return Err(op_failed("rdma_create_ep(client)"));
|
||||
}
|
||||
|
||||
// Post a receive for the 16-byte RemoteInfo before connecting.
|
||||
let mut meta = RemoteInfo::default();
|
||||
let meta_ptr = (&mut meta as *mut RemoteInfo).cast::<c_void>();
|
||||
let meta_mr = rdma_reg_msgs(id, meta_ptr, META_LEN);
|
||||
if meta_mr.is_null() {
|
||||
rdma_destroy_ep(id);
|
||||
return Err(op_failed("rdma_reg_msgs(meta)"));
|
||||
}
|
||||
if rdma_post_recv(id, null_mut(), meta_ptr, META_LEN, meta_mr) != 0 {
|
||||
rdma_destroy_ep(id);
|
||||
return Err(op_failed("rdma_post_recv(meta)"));
|
||||
}
|
||||
|
||||
let mut cp = conn_param();
|
||||
if rdma_connect(id, &mut cp) != 0 {
|
||||
rdma_destroy_ep(id);
|
||||
return Err(op_failed("rdma_connect"));
|
||||
}
|
||||
wait_comp(rdma_get_recv_comp, id, "recv(meta)")?;
|
||||
rdma_dereg_mr(meta_mr);
|
||||
|
||||
let device = query_device(id);
|
||||
Ok((
|
||||
RealRdmaContext { id, device },
|
||||
meta.addr,
|
||||
meta.rkey,
|
||||
meta.len as usize,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a local buffer (LOCAL_WRITE) as the destination of an RDMA READ.
|
||||
/// Returns the engine's `MemoryRegion` plus the raw `ibv_mr` needed to post.
|
||||
pub fn register_memory(&self, buf: &mut [u8]) -> RdmaResult<(MemoryRegion, *mut ibv_mr)> {
|
||||
unsafe {
|
||||
let mr = rdma_reg_msgs(self.id, buf.as_mut_ptr().cast(), buf.len());
|
||||
if mr.is_null() {
|
||||
return Err(op_failed("rdma_reg_msgs(dest)"));
|
||||
}
|
||||
Ok((
|
||||
MemoryRegion {
|
||||
addr: buf.as_ptr() as u64,
|
||||
rkey: (*mr).rkey,
|
||||
lkey: (*mr).lkey,
|
||||
size: buf.len(),
|
||||
registered: true,
|
||||
},
|
||||
mr,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Post a genuine `IBV_WR_RDMA_READ`: pull `buf.len()` bytes from the remote
|
||||
/// `{remote_addr, rkey}` into the local buffer described by `mr`.
|
||||
pub fn post_read(
|
||||
&self,
|
||||
buf: &mut [u8],
|
||||
mr: *mut ibv_mr,
|
||||
remote_addr: u64,
|
||||
rkey: u32,
|
||||
wr_id: u64,
|
||||
) -> RdmaResult<()> {
|
||||
unsafe {
|
||||
let flags = ibv_send_flags::IBV_SEND_SIGNALED.0 as c_int;
|
||||
if rdma_post_read(
|
||||
self.id,
|
||||
wr_id as *mut c_void,
|
||||
buf.as_mut_ptr().cast(),
|
||||
buf.len(),
|
||||
mr,
|
||||
flags,
|
||||
remote_addr,
|
||||
rkey,
|
||||
) != 0
|
||||
{
|
||||
return Err(op_failed("rdma_post_read"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait for the RDMA READ completion (it lands on the send queue).
|
||||
pub fn poll_completion(&self) -> RdmaResult<WorkCompletion> {
|
||||
unsafe {
|
||||
let wc = wait_comp(rdma_get_send_comp, self.id, "send_comp(read)")?;
|
||||
Ok(WorkCompletion {
|
||||
wr_id: wc.wr_id,
|
||||
status: CompletionStatus::from(wc.status as u32),
|
||||
opcode: RdmaOp::Read,
|
||||
byte_len: wc.byte_len,
|
||||
imm_data: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn device_info(&self) -> &RdmaDeviceInfo {
|
||||
&self.device
|
||||
}
|
||||
|
||||
/// Signal the responder we are done (1-byte send) so it can tear down, then
|
||||
/// disconnect.
|
||||
pub fn finish(&self) {
|
||||
unsafe {
|
||||
let mut done = [1u8; 1];
|
||||
let mr = rdma_reg_msgs(self.id, done.as_mut_ptr().cast(), 1);
|
||||
if !mr.is_null() {
|
||||
if rdma_post_send(self.id, null_mut(), done.as_mut_ptr().cast(), 1, mr, 0) == 0 {
|
||||
let _ = wait_comp(rdma_get_send_comp, self.id, "send_comp(done)");
|
||||
}
|
||||
rdma_dereg_mr(mr);
|
||||
}
|
||||
rdma_disconnect(self.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RealRdmaContext {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if !self.id.is_null() {
|
||||
rdma_destroy_ep(self.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A throwaway loopback RDMA-READ target: registers `data` for `REMOTE_READ`,
|
||||
/// accepts one client, hands it `{addr, rkey, len}`, and serves until the client
|
||||
/// signals done. Blocking — run on a thread; `data` must outlive the call so the
|
||||
/// client's reads see real bytes.
|
||||
pub struct RealResponder;
|
||||
|
||||
impl RealResponder {
|
||||
pub fn serve_once(
|
||||
ip: &str,
|
||||
port: u16,
|
||||
data: &mut [u8],
|
||||
ready: impl FnOnce(),
|
||||
) -> RdmaResult<()> {
|
||||
unsafe {
|
||||
let node = CString::new(ip).map_err(|_| op_failed("bad ip"))?;
|
||||
let svc = CString::new(port.to_string()).unwrap();
|
||||
let mut hints: rdma_addrinfo = std::mem::zeroed();
|
||||
hints.ai_flags = RAI_PASSIVE as c_int;
|
||||
hints.ai_port_space = rdma_port_space::RDMA_PS_TCP as c_int;
|
||||
let mut res: *mut rdma_addrinfo = null_mut();
|
||||
if rdma_getaddrinfo(node.as_ptr(), svc.as_ptr(), &hints, &mut res) != 0 {
|
||||
return Err(op_failed("rdma_getaddrinfo(server)"));
|
||||
}
|
||||
let mut attr = qp_init_attr();
|
||||
let mut listen_id: *mut rdma_cm_id = null_mut();
|
||||
let r = rdma_create_ep(&mut listen_id, res, null_mut(), &mut attr);
|
||||
rdma_freeaddrinfo(res);
|
||||
if r != 0 {
|
||||
return Err(op_failed("rdma_create_ep(server)"));
|
||||
}
|
||||
if rdma_listen(listen_id, 1) != 0 {
|
||||
rdma_destroy_ep(listen_id);
|
||||
return Err(op_failed("rdma_listen"));
|
||||
}
|
||||
ready(); // the listener is up; let the client connect
|
||||
|
||||
let mut id: *mut rdma_cm_id = null_mut();
|
||||
if rdma_get_request(listen_id, &mut id) != 0 {
|
||||
rdma_destroy_ep(listen_id);
|
||||
return Err(op_failed("rdma_get_request"));
|
||||
}
|
||||
|
||||
// Expose the source buffer for REMOTE_READ.
|
||||
let src_mr = rdma_reg_read(id, data.as_mut_ptr().cast(), data.len());
|
||||
if src_mr.is_null() {
|
||||
rdma_destroy_ep(id);
|
||||
rdma_destroy_ep(listen_id);
|
||||
return Err(op_failed("rdma_reg_read"));
|
||||
}
|
||||
|
||||
let mut meta = RemoteInfo {
|
||||
addr: data.as_ptr() as u64,
|
||||
rkey: (*src_mr).rkey,
|
||||
len: data.len() as u32,
|
||||
};
|
||||
let meta_ptr = (&mut meta as *mut RemoteInfo).cast::<c_void>();
|
||||
let meta_mr = rdma_reg_msgs(id, meta_ptr, META_LEN);
|
||||
let mut done = [0u8; 1];
|
||||
let done_mr = rdma_reg_msgs(id, done.as_mut_ptr().cast(), 1);
|
||||
if meta_mr.is_null() || done_mr.is_null() {
|
||||
return Err(op_failed("rdma_reg_msgs(server)"));
|
||||
}
|
||||
// Post the done-signal receive before accepting.
|
||||
if rdma_post_recv(id, null_mut(), done.as_mut_ptr().cast(), 1, done_mr) != 0 {
|
||||
return Err(op_failed("rdma_post_recv(done)"));
|
||||
}
|
||||
|
||||
let mut cp = conn_param();
|
||||
if rdma_accept(id, &mut cp) != 0 {
|
||||
return Err(op_failed("rdma_accept"));
|
||||
}
|
||||
|
||||
// Hand the client the source MR coordinates.
|
||||
if rdma_post_send(id, null_mut(), meta_ptr, META_LEN, meta_mr, 0) != 0 {
|
||||
return Err(op_failed("rdma_post_send(meta)"));
|
||||
}
|
||||
wait_comp(rdma_get_send_comp, id, "send_comp(meta)")?;
|
||||
|
||||
// Keep src_mr/data alive until the client finishes its read.
|
||||
wait_comp(rdma_get_recv_comp, id, "recv_comp(done)")?;
|
||||
|
||||
rdma_disconnect(id);
|
||||
rdma_dereg_mr(src_mr);
|
||||
rdma_dereg_mr(meta_mr);
|
||||
rdma_dereg_mr(done_mr);
|
||||
rdma_destroy_ep(id);
|
||||
rdma_destroy_ep(listen_id);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"v":1}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "ad39d0cba38a5ffe57c3596cfca7a4476c41b61c"
|
||||
},
|
||||
"path_in_vcs": ""
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
name: RDMA-SYS-CI
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
push:
|
||||
branches: [master]
|
||||
schedule: [cron: "0 */24 * * *"]
|
||||
|
||||
env:
|
||||
CI_RUST_TOOLCHAIN: 1.61.0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Git Sumbodule Update
|
||||
run: |
|
||||
git submodule update --remote --recursive
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# Install libibverbs-dev as dependency automatically
|
||||
sudo apt-get install -y librdmacm-dev
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.CI_RUST_TOOLCHAIN }}
|
||||
override: true
|
||||
- name: Test
|
||||
run: |
|
||||
./rdma-env-setup/scripts/setup.sh
|
||||
./scripts/run.sh
|
||||
- name: Setup tmate session
|
||||
if: ${{ failure() }}
|
||||
uses: mxschmitt/action-tmate@v3
|
||||
|
||||
fmt:
|
||||
name: Fmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.CI_RUST_TOOLCHAIN }}
|
||||
override: true
|
||||
- run: rustup component add rustfmt
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
@@ -0,0 +1,10 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
@@ -0,0 +1,4 @@
|
||||
[submodule "rdma-env-setup"]
|
||||
path = rdma-env-setup
|
||||
url = https://github.com/datenlord/rdma-env-setup.git
|
||||
branch = main
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.59.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
"peeking_take_while",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdma-sys"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"libc",
|
||||
"memoffset",
|
||||
"paste",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
|
||||
dependencies = [
|
||||
"either",
|
||||
"libc",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
@@ -0,0 +1,35 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "rdma-sys"
|
||||
version = "0.3.0"
|
||||
authors = ["Pu Wang <nicolas.weeks@gmail.com>"]
|
||||
description = "Rdma ibverbs lib Rust binding"
|
||||
license-file = "LICENSE"
|
||||
repository = "https://github.com/datenlord/rdma-sys"
|
||||
resolver = "2"
|
||||
|
||||
[dependencies.libc]
|
||||
version = "0.2"
|
||||
|
||||
[dependencies.memoffset]
|
||||
version = "0.6"
|
||||
|
||||
[dependencies.paste]
|
||||
version = "1.0"
|
||||
|
||||
[build-dependencies.bindgen]
|
||||
version = "0.69.4"
|
||||
|
||||
[build-dependencies.pkg-config]
|
||||
version = "0.3"
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "rdma-sys"
|
||||
version = "0.3.0"
|
||||
authors = ["Pu Wang <nicolas.weeks@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "Rdma ibverbs lib Rust binding"
|
||||
license-file = "LICENSE"
|
||||
repository = "https://github.com/datenlord/rdma-sys"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
memoffset = "0.6"
|
||||
paste = "1.0"
|
||||
# intrusive-collections = "0.9"
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = "0.59.2"
|
||||
pkg-config = "0.3"
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 datenlord
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,3 @@
|
||||
# Rdma ibverbs lib Rust binding
|
||||
|
||||
This lib is the ibverbs low-level Rust binding. As inline function and nested structure are not handled properly in the automatic bind generator, we deal with them case by case manually.
|
||||
@@ -0,0 +1,161 @@
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
fn link_rdma_core(lib_name: &str, pkg_name: &str, version: &str, include_paths: &mut Vec<String>) {
|
||||
let result: _ = pkg_config::Config::new()
|
||||
.atleast_version(version)
|
||||
.statik(false)
|
||||
.probe(lib_name);
|
||||
|
||||
let lib = result.unwrap_or_else(|_| panic!("please install {pkg_name} {version})"));
|
||||
println!("found {pkg_name} {}", lib.version);
|
||||
|
||||
for path in lib.include_paths {
|
||||
let path = path.to_str().expect("non-utf8 path");
|
||||
include_paths.push(path.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut include_paths: Vec<String> = Vec::new();
|
||||
|
||||
{
|
||||
let lib_name = "libibverbs";
|
||||
let pkg_name = "libibverbs-dev";
|
||||
let version = "1.8.28";
|
||||
link_rdma_core(lib_name, pkg_name, version, &mut include_paths);
|
||||
}
|
||||
|
||||
{
|
||||
let lib_name = "librdmacm";
|
||||
let pkg_name = "librdmacm-dev";
|
||||
let version = "1.2.28";
|
||||
link_rdma_core(lib_name, pkg_name, version, &mut include_paths);
|
||||
}
|
||||
|
||||
{
|
||||
include_paths.sort_unstable();
|
||||
include_paths.dedup_by(|x, first| x == first);
|
||||
include_paths.push("/usr/include".into());
|
||||
println!("include paths: {:?}", include_paths);
|
||||
}
|
||||
|
||||
let include_args = include_paths.iter().map(|p| format!("-I{}", p));
|
||||
|
||||
let bindings = bindgen::Builder::default()
|
||||
.clang_args(include_args)
|
||||
.header("src/bindings.h")
|
||||
.allowlist_function("ibv_.*")
|
||||
.allowlist_type("ibv_.*")
|
||||
.allowlist_function("rdma_.*")
|
||||
.allowlist_type("rdma_.*")
|
||||
.allowlist_type("verbs_.*")
|
||||
.allowlist_type("ib_uverbs_access_flags")
|
||||
//.allowlist_type("verbs_devices_ops")
|
||||
//.allowlist_var("verbs_provider_.*")
|
||||
.blocklist_type("in6_addr")
|
||||
.opaque_type("pthread_.*")
|
||||
.blocklist_type("sockaddr.*")
|
||||
.blocklist_type("timespec")
|
||||
.blocklist_type("ibv_ah_attr")
|
||||
.blocklist_type("ibv_async_event")
|
||||
.blocklist_type("ibv_flow_spec")
|
||||
.blocklist_type("ibv_gid")
|
||||
.blocklist_type("ibv_global_route")
|
||||
.blocklist_type("ibv_mw_bind_info")
|
||||
.blocklist_type("ibv_ops_wr")
|
||||
.blocklist_type("ibv_send_wr")
|
||||
.blocklist_type("ibv_wc")
|
||||
.blocklist_type("rdma_addr")
|
||||
.blocklist_type("rdma_cm_event")
|
||||
.blocklist_type("rdma_ib_addr")
|
||||
.blocklist_type("rdma_ud_param")
|
||||
// Following ENUM will used with bitwise-or
|
||||
// including flags, mask, caps, bits, fields, size
|
||||
.bitfield_enum("ibv_device_cap_flags")
|
||||
.bitfield_enum("ibv_odp_transport_cap_bits")
|
||||
.bitfield_enum("ibv_odp_general_caps")
|
||||
.bitfield_enum("ibv_rx_hash_function_flags")
|
||||
.bitfield_enum("ibv_rx_hash_fields")
|
||||
.bitfield_enum("ibv_raw_packet_caps")
|
||||
.bitfield_enum("ibv_tm_cap_flags")
|
||||
.bitfield_enum("ibv_pci_atomic_op_size")
|
||||
.bitfield_enum("ibv_port_cap_flags")
|
||||
.bitfield_enum("ibv_port_cap_flags2")
|
||||
.bitfield_enum("ibv_create_cq_wc_flags")
|
||||
.bitfield_enum("ibv_wc_flags")
|
||||
.bitfield_enum("ibv_access_flags")
|
||||
.bitfield_enum("ibv_xrcd_init_attr_mask")
|
||||
.bitfield_enum("ibv_rereg_mr_flags")
|
||||
.bitfield_enum("ibv_srq_attr_mask")
|
||||
.bitfield_enum("ibv_srq_init_attr_mask") // TODO: need to be bitfield?
|
||||
.bitfield_enum("ibv_wq_init_attr_mask")
|
||||
.bitfield_enum("ibv_wq_flags")
|
||||
.bitfield_enum("ibv_wq_attr_mask")
|
||||
.bitfield_enum("ibv_ind_table_init_attr_mask")
|
||||
.bitfield_enum("ibv_qp_init_attr_mask") // TODO: need to be bitfield?
|
||||
.bitfield_enum("ibv_qp_create_flags")
|
||||
.bitfield_enum("ibv_qp_create_send_ops_flags")
|
||||
.bitfield_enum("ibv_qp_open_attr_mask")
|
||||
.bitfield_enum("ibv_qp_attr_mask")
|
||||
.bitfield_enum("ibv_send_flags")
|
||||
.bitfield_enum("ibv_ops_flags")
|
||||
.bitfield_enum("ibv_cq_attr_mask")
|
||||
.bitfield_enum("ibv_flow_flags")
|
||||
.bitfield_enum("ibv_flow_action_esp_mask")
|
||||
.bitfield_enum("ibv_cq_init_attr_mask")
|
||||
.bitfield_enum("ibv_create_cq_attr_flags")
|
||||
.bitfield_enum("ibv_parent_domain_init_attr_mask")
|
||||
.bitfield_enum("ibv_read_counters_flags")
|
||||
.bitfield_enum("ibv_values_mask")
|
||||
.bitfield_enum("ib_uverbs_access_flags")
|
||||
.bitfield_enum("rdma_cm_join_mc_attr_mask")
|
||||
.bitfield_enum("rdma_cm_mc_join_flags")
|
||||
// Following ENUM will be const in a sub-mod
|
||||
.constified_enum_module("ibv_node_type")
|
||||
.constified_enum_module("ibv_transport_type")
|
||||
.constified_enum_module("ibv_atomic_cap")
|
||||
.constified_enum_module("ibv_mtu")
|
||||
.constified_enum_module("ibv_port_state")
|
||||
.constified_enum_module("ibv_wc_status")
|
||||
.constified_enum_module("ibv_wc_opcode")
|
||||
.constified_enum_module("ibv_mw_type")
|
||||
.constified_enum_module("ibv_rate")
|
||||
.constified_enum_module("ibv_srq_type")
|
||||
.constified_enum_module("ibv_wq_type")
|
||||
.constified_enum_module("ibv_wq_state")
|
||||
.constified_enum_module("ibv_qp_type")
|
||||
.constified_enum_module("ibv_qp_state")
|
||||
.constified_enum_module("ibv_mig_state")
|
||||
.constified_enum_module("ibv_wr_opcode")
|
||||
.constified_enum_module("ibv_ops_wr_opcode")
|
||||
.constified_enum_module("ibv_flow_attr_type")
|
||||
.constified_enum_module("ibv_flow_spec_type")
|
||||
.constified_enum_module("ibv_counter_description")
|
||||
.constified_enum_module("ibv_rereg_mr_err_code")
|
||||
.constified_enum_module("ib_uverbs_advise_mr_advice")
|
||||
.constified_enum_module("rdma_cm_event_type")
|
||||
.constified_enum_module("rdma_driver_id")
|
||||
.constified_enum_module("rdma_port_space")
|
||||
.rustified_enum("ibv_event_type")
|
||||
// unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable
|
||||
// for example: `pub eth: ibv_flow_spec_eth`
|
||||
// note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
|
||||
.derive_copy(true)
|
||||
.derive_debug(false)
|
||||
.derive_default(false)
|
||||
.generate_comments(false)
|
||||
//.generate_inline_functions(true)
|
||||
//.default_macro_constant_type(bindgen::MacroTypeVariation::Unsigned)
|
||||
.prepend_enum_name(false)
|
||||
.disable_untagged_union()
|
||||
.generate()
|
||||
.expect("Unable to generate bindings");
|
||||
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let dest_path = Path::new(&out_dir).join("bindings.rs");
|
||||
|
||||
bindings
|
||||
.write_to_file(dest_path)
|
||||
.expect("Could not write bindings");
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
//! This demo shows how to establish a connection between server and client
|
||||
//! and send msg to the other end.
|
||||
//!
|
||||
//! You can try this example by running:
|
||||
//!
|
||||
//! cargo run --example server
|
||||
//!
|
||||
//! And then start client in another terminal by running:
|
||||
//!
|
||||
//! cargo run --example client <server_ip> <port>
|
||||
//!
|
||||
//! The default port is 7471.
|
||||
|
||||
use rdma_sys::*;
|
||||
use std::{env, process::exit, ptr::null_mut};
|
||||
|
||||
fn run(ip: &str, port: &str) -> i32 {
|
||||
let mut send_msg = vec![1_u8; 16];
|
||||
let mut recv_msg = vec![0_u8; 16];
|
||||
let mut hints = unsafe { std::mem::zeroed::<rdma_addrinfo>() };
|
||||
let mut res: *mut rdma_addrinfo = null_mut();
|
||||
|
||||
hints.ai_port_space = rdma_port_space::RDMA_PS_TCP as i32;
|
||||
let mut ret =
|
||||
unsafe { rdma_getaddrinfo(ip.as_ptr().cast(), port.as_ptr().cast(), &hints, &mut res) };
|
||||
|
||||
if ret != 0 {
|
||||
println!("rdma_getaddrinfo");
|
||||
return ret;
|
||||
}
|
||||
|
||||
let mut attr = unsafe { std::mem::zeroed::<ibv_qp_init_attr>() };
|
||||
let mut id: *mut rdma_cm_id = null_mut();
|
||||
attr.cap.max_send_wr = 1;
|
||||
attr.cap.max_recv_wr = 1;
|
||||
attr.cap.max_send_sge = 1;
|
||||
attr.cap.max_recv_sge = 1;
|
||||
attr.cap.max_inline_data = 16;
|
||||
attr.qp_context = id.cast();
|
||||
attr.sq_sig_all = 1;
|
||||
ret = unsafe { rdma_create_ep(&mut id, res, null_mut(), &mut attr) };
|
||||
// Check to see if we got inline data allowed or not
|
||||
let mut send_flags = 0_u32;
|
||||
if attr.cap.max_inline_data >= 16 {
|
||||
send_flags = ibv_send_flags::IBV_SEND_INLINE.0;
|
||||
} else {
|
||||
println!("rdma_client: device doesn't support IBV_SEND_INLINE, using sge sends");
|
||||
}
|
||||
|
||||
if ret != 0 {
|
||||
println!("rdma_create_ep");
|
||||
unsafe {
|
||||
rdma_freeaddrinfo(res);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
let mr = unsafe { rdma_reg_msgs(id, recv_msg.as_mut_ptr().cast(), 16) };
|
||||
if mr.is_null() {
|
||||
println!("rdma_reg_msgs for recv_msg");
|
||||
unsafe {
|
||||
rdma_destroy_ep(id);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
let mut send_mr = null_mut();
|
||||
if (send_flags & ibv_send_flags::IBV_SEND_INLINE.0) as u32 == 0 {
|
||||
println!("flags {:?}", send_flags);
|
||||
send_mr = unsafe { rdma_reg_msgs(id, send_msg.as_mut_ptr().cast(), 16) };
|
||||
if send_mr.is_null() {
|
||||
println!("rdma_reg_msgs for send_msg");
|
||||
unsafe {
|
||||
rdma_dereg_mr(mr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ret = unsafe { rdma_post_recv(id, null_mut(), recv_msg.as_mut_ptr().cast(), 16, mr) };
|
||||
if ret != 0 {
|
||||
println!("rdma_post_recv");
|
||||
if (send_flags & ibv_send_flags::IBV_SEND_INLINE.0) as u32 == 0 {
|
||||
unsafe { rdma_dereg_mr(send_mr) };
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = unsafe { rdma_connect(id, null_mut()) };
|
||||
if ret != 0 {
|
||||
println!("rdma_connect");
|
||||
unsafe {
|
||||
rdma_disconnect(id);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = unsafe {
|
||||
rdma_post_send(
|
||||
id,
|
||||
null_mut(),
|
||||
send_msg.as_mut_ptr().cast(),
|
||||
16,
|
||||
send_mr,
|
||||
send_flags.try_into().unwrap(),
|
||||
)
|
||||
};
|
||||
if ret != 0 {
|
||||
println!("rdma_post_send");
|
||||
unsafe {
|
||||
rdma_disconnect(id);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
let mut wc = unsafe { std::mem::zeroed::<ibv_wc>() };
|
||||
while ret == 0 {
|
||||
ret = unsafe { rdma_get_send_comp(id, &mut wc) };
|
||||
}
|
||||
if ret < 0 {
|
||||
println!("rdma_get_send_comp");
|
||||
unsafe {
|
||||
rdma_disconnect(id);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
while ret == 0 {
|
||||
ret = unsafe { rdma_get_recv_comp(id, &mut wc) };
|
||||
}
|
||||
println!("rdma_client: recv msg : {:?}", recv_msg);
|
||||
if ret < 0 {
|
||||
println!("rdma_get_recv_comp");
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("rdma_client: start");
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() != 3 {
|
||||
println!("usage : cargo run --example client <server_ip> <port>");
|
||||
println!("input : {:?}", args);
|
||||
exit(-1);
|
||||
}
|
||||
let ip = args.get(1).unwrap().as_str();
|
||||
let port = args.get(2).unwrap().as_str();
|
||||
|
||||
let ret = run(ip, port);
|
||||
|
||||
if ret != 0 {
|
||||
println!(
|
||||
"rdma_client: ret error {:?}",
|
||||
std::io::Error::from_raw_os_error(-ret)
|
||||
);
|
||||
if ret == -1 {
|
||||
println!(
|
||||
"rdma_client: last os error {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
}
|
||||
println!("rdma_client: end");
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
//! This demo shows how to establish a connection between server and client
|
||||
//! and send msg to the other end.
|
||||
//!
|
||||
//! You can try this example by running:
|
||||
//!
|
||||
//! cargo run --example server
|
||||
//!
|
||||
//! And then start client in another terminal by running:
|
||||
//!
|
||||
//! cargo run --example client <server_ip> <port>
|
||||
//!
|
||||
//! The default port is 7471.
|
||||
|
||||
use rdma_sys::*;
|
||||
use std::ptr::null_mut;
|
||||
|
||||
static SERVER: &str = "0.0.0.0\0";
|
||||
static PORT: &str = "7471\0";
|
||||
|
||||
fn run() -> i32 {
|
||||
let mut send_msg = vec![1_u8; 16];
|
||||
let mut recv_msg = vec![0_u8; 16];
|
||||
let mut hints = unsafe { std::mem::zeroed::<rdma_addrinfo>() };
|
||||
let mut res: *mut rdma_addrinfo = null_mut();
|
||||
hints.ai_flags = RAI_PASSIVE.try_into().unwrap();
|
||||
hints.ai_port_space = rdma_port_space::RDMA_PS_TCP.try_into().unwrap();
|
||||
let mut ret = unsafe {
|
||||
rdma_getaddrinfo(
|
||||
SERVER.as_ptr().cast(),
|
||||
PORT.as_ptr().cast(),
|
||||
&hints,
|
||||
&mut res,
|
||||
)
|
||||
};
|
||||
|
||||
if ret != 0 {
|
||||
println!("rdma_getaddrinfo");
|
||||
return ret;
|
||||
}
|
||||
|
||||
let mut listen_id = null_mut();
|
||||
let mut id = null_mut();
|
||||
|
||||
let mut init_attr = unsafe { std::mem::zeroed::<ibv_qp_init_attr>() };
|
||||
init_attr.cap.max_send_wr = 1;
|
||||
init_attr.cap.max_recv_wr = 1;
|
||||
init_attr.cap.max_send_sge = 1;
|
||||
init_attr.cap.max_recv_sge = 1;
|
||||
init_attr.cap.max_inline_data = 16;
|
||||
init_attr.sq_sig_all = 1;
|
||||
ret = unsafe { rdma_create_ep(&mut listen_id, res, null_mut(), &mut init_attr) };
|
||||
// Check to see if we got inline data allowed or not
|
||||
if ret != 0 {
|
||||
println!("rdma_create_ep");
|
||||
unsafe {
|
||||
rdma_freeaddrinfo(res);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
ret = unsafe { rdma_listen(listen_id, 0) };
|
||||
if ret != 0 {
|
||||
println!("rdma_listen");
|
||||
unsafe {
|
||||
rdma_destroy_ep(listen_id);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = unsafe { rdma_get_request(listen_id, &mut id) };
|
||||
if ret != 0 {
|
||||
println!("rdma_get_request");
|
||||
unsafe {
|
||||
rdma_destroy_ep(listen_id);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
let mut qp_attr = unsafe { std::mem::zeroed::<ibv_qp_attr>() };
|
||||
ret = unsafe {
|
||||
ibv_query_qp(
|
||||
(*id).qp,
|
||||
&mut qp_attr,
|
||||
ibv_qp_attr_mask::IBV_QP_CAP.0.try_into().unwrap(),
|
||||
&mut init_attr,
|
||||
)
|
||||
};
|
||||
|
||||
if ret != 0 {
|
||||
println!("ibv_query_qp");
|
||||
unsafe {
|
||||
rdma_destroy_ep(id);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
let mut send_flags = 0_u32;
|
||||
if init_attr.cap.max_inline_data >= 16 {
|
||||
send_flags = ibv_send_flags::IBV_SEND_INLINE.0;
|
||||
} else {
|
||||
println!("rdma_server: device doesn't support IBV_SEND_INLINE, using sge sends");
|
||||
}
|
||||
|
||||
let recv_mr = unsafe { rdma_reg_msgs(id, recv_msg.as_mut_ptr().cast(), 16) };
|
||||
if recv_mr.is_null() {
|
||||
ret = -1;
|
||||
println!("rdma_reg_msgs for recv_msg");
|
||||
unsafe {
|
||||
rdma_dereg_mr(recv_mr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
let mut send_mr = null_mut();
|
||||
if (send_flags & ibv_send_flags::IBV_SEND_INLINE.0) == 0 {
|
||||
send_mr = unsafe { rdma_reg_msgs(id, send_msg.as_mut_ptr().cast(), 16) };
|
||||
if send_mr.is_null() {
|
||||
ret = -1;
|
||||
println!("rdma_reg_msgs for send_msg");
|
||||
unsafe {
|
||||
rdma_dereg_mr(recv_mr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = unsafe { rdma_post_recv(id, null_mut(), recv_msg.as_mut_ptr().cast(), 16, recv_mr) };
|
||||
|
||||
if ret != 0 {
|
||||
println!("rdma_post_recv");
|
||||
unsafe {
|
||||
rdma_dereg_mr(recv_mr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = unsafe { rdma_accept(id, null_mut()) };
|
||||
if ret != 0 {
|
||||
println!("rdma_accept");
|
||||
if (send_flags & ibv_send_flags::IBV_SEND_INLINE.0) == 0 {
|
||||
unsafe { rdma_dereg_mr(send_mr) };
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
let mut wc = unsafe { std::mem::zeroed::<ibv_wc>() };
|
||||
while ret == 0 {
|
||||
ret = unsafe { rdma_get_recv_comp(id, &mut wc) };
|
||||
}
|
||||
if ret < 0 {
|
||||
println!("rdma_get_recv_comp");
|
||||
unsafe {
|
||||
rdma_disconnect(id);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
println!("rdma_server: recv msg : {:?}", recv_msg);
|
||||
ret = unsafe {
|
||||
rdma_post_send(
|
||||
id,
|
||||
null_mut(),
|
||||
send_msg.as_mut_ptr().cast(),
|
||||
16,
|
||||
send_mr,
|
||||
send_flags.try_into().unwrap(),
|
||||
)
|
||||
};
|
||||
if ret != 0 {
|
||||
println!("rdma_post_send");
|
||||
unsafe {
|
||||
rdma_disconnect(id);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
while ret == 0 {
|
||||
ret = unsafe { rdma_get_send_comp(id, &mut wc) };
|
||||
}
|
||||
if ret < 0 {
|
||||
println!("rdma_get_send_comp");
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("rdma_server: start");
|
||||
let ret = run();
|
||||
if ret != 0 {
|
||||
println!(
|
||||
"rdma_server: ret error {:?}",
|
||||
std::io::Error::from_raw_os_error(-ret)
|
||||
);
|
||||
if ret == -1 {
|
||||
println!(
|
||||
"rdma_server: last os error {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
}
|
||||
println!("rdma_server: end");
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#! /bin/sh
|
||||
|
||||
RXE_DEV=rxe_eth0
|
||||
|
||||
# Remove existing devices if any
|
||||
sudo rdma link delete $RXE_DEV
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o xtrace
|
||||
|
||||
if [ `ifconfig -s | grep -c '^e'` -eq 0 ]; then
|
||||
echo "no eth device"
|
||||
exit 1
|
||||
elif [ `ifconfig -s | grep -c '^e'` -gt 1 ]; then
|
||||
echo "multiple eth devices, select the first one"
|
||||
ifconfig -s | grep '^e'
|
||||
fi
|
||||
|
||||
ETH_DEV=`ifconfig -s | grep '^e' | cut -d ' ' -f 1 | head -n 1`
|
||||
ETH_IP=`ifconfig $ETH_DEV | grep inet | grep -v inet6 | awk '{print $2}' | tr -d "addr:"`
|
||||
CM_PORT=7471
|
||||
# Setup soft-roce device
|
||||
sudo rdma link add $RXE_DEV type rxe netdev $ETH_DEV
|
||||
rdma link | grep $RXE_DEV
|
||||
|
||||
cargo test --all
|
||||
cargo run --example server &
|
||||
sleep 1 &&
|
||||
cargo run --example client $ETH_IP $CM_PORT
|
||||
@@ -0,0 +1,3 @@
|
||||
#include <infiniband/verbs.h>
|
||||
#include <rdma/rdma_cma.h>
|
||||
#include <rdma/rdma_verbs.h>
|
||||
@@ -0,0 +1,16 @@
|
||||
#![deny(warnings)]
|
||||
#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
|
||||
#![allow(deref_nullptr)] // TODO(fxbug.dev/74605): Remove once bindgen is fixed.
|
||||
#![allow(clippy::missing_safety_doc, clippy::too_many_arguments)]
|
||||
|
||||
use libc::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
|
||||
mod opcode;
|
||||
mod types;
|
||||
mod verbs;
|
||||
|
||||
pub use self::opcode::*;
|
||||
pub use self::types::*;
|
||||
pub use self::verbs::*;
|
||||
@@ -0,0 +1,103 @@
|
||||
pub mod ibv_opcode {
|
||||
use paste::paste;
|
||||
pub type Type = std::os::raw::c_int;
|
||||
macro_rules! concat_ibv_opcode {
|
||||
($transport: expr, $op : expr ) => {
|
||||
paste! {
|
||||
pub const [<IBV_OPCODE_ $transport _ $op>]: Type = [<IBV_OPCODE_ $transport>] + [<IBV_OPCODE_ $op>] ;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* transport types -- just used to define real constants */
|
||||
pub const IBV_OPCODE_RC: Type = 0x00;
|
||||
pub const IBV_OPCODE_UC: Type = 0x20;
|
||||
pub const IBV_OPCODE_RD: Type = 0x40;
|
||||
pub const IBV_OPCODE_UD: Type = 0x60;
|
||||
/* operations -- just used to define real constants */
|
||||
pub const IBV_OPCODE_SEND_FIRST: Type = 0x00;
|
||||
pub const IBV_OPCODE_SEND_MIDDLE: Type = 0x01;
|
||||
pub const IBV_OPCODE_SEND_LAST: Type = 0x02;
|
||||
pub const IBV_OPCODE_SEND_LAST_WITH_IMMEDIATE: Type = 0x03;
|
||||
pub const IBV_OPCODE_SEND_ONLY: Type = 0x04;
|
||||
pub const IBV_OPCODE_SEND_ONLY_WITH_IMMEDIATE: Type = 0x05;
|
||||
pub const IBV_OPCODE_RDMA_WRITE_FIRST: Type = 0x06;
|
||||
pub const IBV_OPCODE_RDMA_WRITE_MIDDLE: Type = 0x07;
|
||||
pub const IBV_OPCODE_RDMA_WRITE_LAST: Type = 0x08;
|
||||
pub const IBV_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE: Type = 0x09;
|
||||
pub const IBV_OPCODE_RDMA_WRITE_ONLY: Type = 0x0a;
|
||||
pub const IBV_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE: Type = 0x0b;
|
||||
pub const IBV_OPCODE_RDMA_READ_REQUEST: Type = 0x0c;
|
||||
pub const IBV_OPCODE_RDMA_READ_RESPONSE_FIRST: Type = 0x0d;
|
||||
pub const IBV_OPCODE_RDMA_READ_RESPONSE_MIDDLE: Type = 0x0e;
|
||||
pub const IBV_OPCODE_RDMA_READ_RESPONSE_LAST: Type = 0x0f;
|
||||
pub const IBV_OPCODE_RDMA_READ_RESPONSE_ONLY: Type = 0x10;
|
||||
pub const IBV_OPCODE_ACKNOWLEDGE: Type = 0x11;
|
||||
pub const IBV_OPCODE_ATOMIC_ACKNOWLEDGE: Type = 0x12;
|
||||
pub const IBV_OPCODE_COMPARE_SWAP: Type = 0x13;
|
||||
pub const IBV_OPCODE_FETCH_ADD: Type = 0x14;
|
||||
|
||||
/* RC */
|
||||
concat_ibv_opcode!(RC, SEND_FIRST);
|
||||
concat_ibv_opcode!(RC, SEND_MIDDLE);
|
||||
concat_ibv_opcode!(RC, SEND_LAST);
|
||||
concat_ibv_opcode!(RC, SEND_LAST_WITH_IMMEDIATE);
|
||||
concat_ibv_opcode!(RC, SEND_ONLY);
|
||||
concat_ibv_opcode!(RC, SEND_ONLY_WITH_IMMEDIATE);
|
||||
concat_ibv_opcode!(RC, RDMA_WRITE_FIRST);
|
||||
concat_ibv_opcode!(RC, RDMA_WRITE_MIDDLE);
|
||||
concat_ibv_opcode!(RC, RDMA_WRITE_LAST);
|
||||
concat_ibv_opcode!(RC, RDMA_WRITE_LAST_WITH_IMMEDIATE);
|
||||
concat_ibv_opcode!(RC, RDMA_WRITE_ONLY);
|
||||
concat_ibv_opcode!(RC, RDMA_WRITE_ONLY_WITH_IMMEDIATE);
|
||||
concat_ibv_opcode!(RC, RDMA_READ_REQUEST);
|
||||
concat_ibv_opcode!(RC, RDMA_READ_RESPONSE_FIRST);
|
||||
concat_ibv_opcode!(RC, RDMA_READ_RESPONSE_MIDDLE);
|
||||
concat_ibv_opcode!(RC, RDMA_READ_RESPONSE_LAST);
|
||||
concat_ibv_opcode!(RC, RDMA_READ_RESPONSE_ONLY);
|
||||
concat_ibv_opcode!(RC, ACKNOWLEDGE);
|
||||
concat_ibv_opcode!(RC, ATOMIC_ACKNOWLEDGE);
|
||||
concat_ibv_opcode!(RC, COMPARE_SWAP);
|
||||
concat_ibv_opcode!(RC, FETCH_ADD);
|
||||
|
||||
/* UC */
|
||||
concat_ibv_opcode!(UC, SEND_FIRST);
|
||||
concat_ibv_opcode!(UC, SEND_MIDDLE);
|
||||
concat_ibv_opcode!(UC, SEND_LAST);
|
||||
concat_ibv_opcode!(UC, SEND_LAST_WITH_IMMEDIATE);
|
||||
concat_ibv_opcode!(UC, SEND_ONLY);
|
||||
concat_ibv_opcode!(UC, SEND_ONLY_WITH_IMMEDIATE);
|
||||
concat_ibv_opcode!(UC, RDMA_WRITE_FIRST);
|
||||
concat_ibv_opcode!(UC, RDMA_WRITE_MIDDLE);
|
||||
concat_ibv_opcode!(UC, RDMA_WRITE_LAST);
|
||||
concat_ibv_opcode!(UC, RDMA_WRITE_LAST_WITH_IMMEDIATE);
|
||||
concat_ibv_opcode!(UC, RDMA_WRITE_ONLY);
|
||||
concat_ibv_opcode!(UC, RDMA_WRITE_ONLY_WITH_IMMEDIATE);
|
||||
|
||||
/* RD */
|
||||
concat_ibv_opcode!(RD, SEND_FIRST);
|
||||
concat_ibv_opcode!(RD, SEND_MIDDLE);
|
||||
concat_ibv_opcode!(RD, SEND_LAST);
|
||||
concat_ibv_opcode!(RD, SEND_LAST_WITH_IMMEDIATE);
|
||||
concat_ibv_opcode!(RD, SEND_ONLY);
|
||||
concat_ibv_opcode!(RD, SEND_ONLY_WITH_IMMEDIATE);
|
||||
concat_ibv_opcode!(RD, RDMA_WRITE_FIRST);
|
||||
concat_ibv_opcode!(RD, RDMA_WRITE_MIDDLE);
|
||||
concat_ibv_opcode!(RD, RDMA_WRITE_LAST);
|
||||
concat_ibv_opcode!(RD, RDMA_WRITE_LAST_WITH_IMMEDIATE);
|
||||
concat_ibv_opcode!(RD, RDMA_WRITE_ONLY);
|
||||
concat_ibv_opcode!(RD, RDMA_WRITE_ONLY_WITH_IMMEDIATE);
|
||||
concat_ibv_opcode!(RD, RDMA_READ_REQUEST);
|
||||
concat_ibv_opcode!(RD, RDMA_READ_RESPONSE_FIRST);
|
||||
concat_ibv_opcode!(RD, RDMA_READ_RESPONSE_MIDDLE);
|
||||
concat_ibv_opcode!(RD, RDMA_READ_RESPONSE_LAST);
|
||||
concat_ibv_opcode!(RD, RDMA_READ_RESPONSE_ONLY);
|
||||
concat_ibv_opcode!(RD, ACKNOWLEDGE);
|
||||
concat_ibv_opcode!(RD, ATOMIC_ACKNOWLEDGE);
|
||||
concat_ibv_opcode!(RD, COMPARE_SWAP);
|
||||
concat_ibv_opcode!(RD, FETCH_ADD);
|
||||
|
||||
/* UD */
|
||||
concat_ibv_opcode!(UD, SEND_ONLY);
|
||||
concat_ibv_opcode!(UD, SEND_ONLY_WITH_IMMEDIATE);
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
use crate::*;
|
||||
|
||||
/// This file defines the types directly or indirectly involving union,
|
||||
/// in that BindGen cannot handle union very well, so mannually define them.
|
||||
|
||||
/// Struct types involve union in <infiniband/verbs.h>
|
||||
|
||||
// ibv_gid related union and struct types
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ibv_gid_global_t {
|
||||
pub subnet_prefix: __be64,
|
||||
pub interface_id: __be64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union ibv_gid {
|
||||
pub raw: [u8; 16],
|
||||
pub global: ibv_gid_global_t,
|
||||
}
|
||||
|
||||
// ibv_async_event related union and struct type
|
||||
#[repr(C)]
|
||||
pub union ibv_async_event_element_t {
|
||||
pub cq: *mut ibv_cq,
|
||||
pub qp: *mut ibv_qp,
|
||||
pub srq: *mut ibv_srq,
|
||||
pub wq: *mut ibv_wq,
|
||||
pub port_num: c_int,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ibv_async_event {
|
||||
pub element: ibv_async_event_element_t,
|
||||
pub event_type: ibv_event_type,
|
||||
}
|
||||
|
||||
// ibv_wc related union and struct types
|
||||
#[repr(C)]
|
||||
pub union imm_data_invalidated_rkey_union_t {
|
||||
/// When (wc_flags & IBV_WC_WITH_IMM): Immediate data in network byte order.
|
||||
pub imm_data: __be32,
|
||||
/// When (wc_flags & IBV_WC_WITH_INV): Stores the invalidated rkey.
|
||||
pub invalidated_rkey: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ibv_wc {
|
||||
pub wr_id: u64,
|
||||
pub status: ibv_wc_status::Type,
|
||||
pub opcode: ibv_wc_opcode::Type,
|
||||
pub vendor_err: u32,
|
||||
pub byte_len: u32,
|
||||
pub imm_data_invalidated_rkey_union: imm_data_invalidated_rkey_union_t,
|
||||
pub qp_num: u32,
|
||||
pub src_qp: u32,
|
||||
pub wc_flags: c_uint,
|
||||
pub pkey_index: u16,
|
||||
pub slid: u16,
|
||||
pub sl: u8,
|
||||
pub dlid_path_bits: u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ibv_global_route {
|
||||
pub dgid: ibv_gid,
|
||||
pub flow_label: u32,
|
||||
pub sgid_index: u8,
|
||||
pub hop_limit: u8,
|
||||
pub traffic_class: u8,
|
||||
}
|
||||
|
||||
// ibv_send_wr related union and struct types
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ibv_mw_bind_info {
|
||||
pub mr: *mut ibv_mr,
|
||||
pub addr: u64,
|
||||
pub length: u64,
|
||||
pub mw_access_flags: ::std::os::raw::c_uint,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct rdma_t {
|
||||
pub remote_addr: u64,
|
||||
pub rkey: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct atomic_t {
|
||||
pub remote_addr: u64,
|
||||
pub compare_add: u64,
|
||||
pub swap: u64,
|
||||
pub rkey: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ud_t {
|
||||
pub ah: *mut ibv_ah,
|
||||
pub remote_qpn: u32,
|
||||
pub remote_qkey: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union wr_t {
|
||||
pub rdma: rdma_t,
|
||||
pub atomic: atomic_t,
|
||||
pub ud: ud_t,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct xrc_t {
|
||||
pub remote_srqn: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union qp_type_t {
|
||||
pub xrc: xrc_t,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct bind_mw_t {
|
||||
pub mw: *mut ibv_mw,
|
||||
pub rkey: u32,
|
||||
pub bind_info: ibv_mw_bind_info,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct tso_t {
|
||||
pub hdr: *mut c_void,
|
||||
pub hdr_sz: u16,
|
||||
pub mss: u16,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union bind_mw_tso_union_t {
|
||||
pub bind_mw: bind_mw_t,
|
||||
pub tso: tso_t,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ibv_send_wr {
|
||||
pub wr_id: u64,
|
||||
pub next: *mut Self,
|
||||
pub sg_list: *mut ibv_sge,
|
||||
pub num_sge: c_int,
|
||||
pub opcode: ibv_wr_opcode::Type,
|
||||
pub send_flags: c_uint,
|
||||
/// When opcode is *_WITH_IMM: Immediate data in network byte order.
|
||||
/// When opcode is *_INV: Stores the rkey to invalidate
|
||||
pub imm_data_invalidated_rkey_union: imm_data_invalidated_rkey_union_t,
|
||||
pub wr: wr_t,
|
||||
pub qp_type: qp_type_t,
|
||||
pub bind_mw_tso_union: bind_mw_tso_union_t,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct add_t {
|
||||
pub recv_wr_id: u64,
|
||||
pub sg_list: *mut ibv_sge,
|
||||
pub num_sge: c_int,
|
||||
pub tag: u64,
|
||||
pub mask: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct tm_t {
|
||||
pub unexpected_cnt: u32,
|
||||
pub handle: u32,
|
||||
pub add: add_t,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ibv_ops_wr {
|
||||
wr_id: u64,
|
||||
next: *mut Self,
|
||||
opcode: ibv_ops_wr_opcode::Type,
|
||||
flags: c_int,
|
||||
tm: tm_t,
|
||||
}
|
||||
|
||||
// ibv_flow_spec related union and struct types
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct hdr_t {
|
||||
pub type_: ibv_flow_spec_type::Type,
|
||||
pub size: u16,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union ibv_flow_spec_union_t {
|
||||
pub hdr: hdr_t,
|
||||
pub eth: ibv_flow_spec_eth,
|
||||
pub ipv4: ibv_flow_spec_ipv4,
|
||||
pub tcp_udp: ibv_flow_spec_tcp_udp,
|
||||
pub ipv4_ext: ibv_flow_spec_ipv4_ext,
|
||||
pub ipv6: ibv_flow_spec_ipv6,
|
||||
pub esp: ibv_flow_spec_esp,
|
||||
pub tunnel: ibv_flow_spec_tunnel,
|
||||
pub gre: ibv_flow_spec_gre,
|
||||
pub mpls: ibv_flow_spec_mpls,
|
||||
pub flow_tag: ibv_flow_spec_action_tag,
|
||||
pub drop: ibv_flow_spec_action_drop,
|
||||
pub handle: ibv_flow_spec_action_handle,
|
||||
pub flow_count: ibv_flow_spec_counter_action,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ibv_flow_spec {
|
||||
pub ibv_flow_spec_union: ibv_flow_spec_union_t,
|
||||
}
|
||||
|
||||
/// Struct types involve union in <rdma/rdma_cma.h>
|
||||
|
||||
// rdma_addr related union and struct types
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct rdma_ib_addr {
|
||||
pub sgid: ibv_gid,
|
||||
pub dgid: ibv_gid,
|
||||
pub pkey: __be16,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union src_addr_union_t {
|
||||
pub src_addr: libc::sockaddr,
|
||||
pub src_sin: libc::sockaddr_in,
|
||||
pub src_sin6: libc::sockaddr_in6,
|
||||
pub src_storage: libc::sockaddr_storage,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union dst_addr_union_t {
|
||||
pub dst_addr: libc::sockaddr,
|
||||
pub dst_sin: libc::sockaddr_in,
|
||||
pub dst_sin6: libc::sockaddr_in6,
|
||||
pub dst_storage: libc::sockaddr_storage,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union addr_union_t {
|
||||
pub ibaddr: rdma_ib_addr,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct rdma_addr {
|
||||
pub src_addr_union: src_addr_union_t,
|
||||
pub dst_addr_union: dst_addr_union_t,
|
||||
pub addr: addr_union_t,
|
||||
}
|
||||
|
||||
/// rdma_cm_event related union and struct types
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ibv_ah_attr {
|
||||
pub grh: ibv_global_route,
|
||||
pub dlid: u16,
|
||||
pub sl: u8,
|
||||
pub src_path_bits: u8,
|
||||
pub static_rate: u8,
|
||||
pub is_global: u8,
|
||||
pub port_num: u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct rdma_ud_param {
|
||||
pub private_data: *const ::std::os::raw::c_void,
|
||||
pub private_data_len: u8,
|
||||
pub ah_attr: ibv_ah_attr,
|
||||
pub qp_num: u32,
|
||||
pub qkey: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union param_t {
|
||||
pub conn: rdma_conn_param,
|
||||
pub ud: rdma_ud_param,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct rdma_cm_event {
|
||||
pub id: *mut rdma_cm_id,
|
||||
pub listen_id: *mut rdma_cm_id,
|
||||
pub event: rdma_cm_event_type::Type,
|
||||
pub status: c_int,
|
||||
pub param: param_t,
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user