rogue
Loading...
Searching...
No Matches
Server.cpp
Go to the documentation of this file.
1
17#include "rogue/Directives.h"
18
20
21#include <infiniband/verbs.h>
22#include <inttypes.h>
23#include <stdint.h>
24#include <string.h>
25
26#include <chrono>
27#include <cstdlib>
28#include <iomanip>
29#include <memory>
30#include <random>
31#include <sstream>
32#include <string>
33#include <thread>
34#include <vector>
35
36#include "rogue/GeneralError.h"
37#include "rogue/GilRelease.h"
38#include "rogue/Logging.h"
43
46
47#ifndef NO_PYTHON
48 #include <boost/python.hpp>
49namespace bp = boost::python;
50#endif
51
52// SSI Start-of-Frame bit set on every received frame
53static const uint8_t SsiSof = 0x02;
54
55// ---------------------------------------------------------------------------
56// Factory
57// ---------------------------------------------------------------------------
58rpr::ServerPtr rpr::Server::create(const std::string& deviceName,
59 uint8_t ibPort,
60 uint8_t gidIndex,
61 uint32_t maxPayload,
62 uint32_t rxQueueDepth) {
63 return std::make_shared<rpr::Server>(
64 deviceName, ibPort, gidIndex, maxPayload, rxQueueDepth);
65}
66
67// ---------------------------------------------------------------------------
68// Constructor
69// ibverbs setup through QP INIT. Receive thread starts in
70// completeConnection() once the FPGA QPN is known.
71// ---------------------------------------------------------------------------
72rpr::Server::Server(const std::string& deviceName,
73 uint8_t ibPort,
74 uint8_t gidIndex,
75 uint32_t maxPayload,
76 uint32_t rxQueueDepth)
77 : rpr::Core(deviceName, ibPort, gidIndex, maxPayload),
78 ris::Master(),
79 ris::Slave(),
80 cq_(nullptr), qp_(nullptr), mr_(nullptr),
81 slab_(nullptr),
82 slabSize_(0),
83 numBufs_(rxQueueDepth),
84 bufSize_(0),
85 hostQpn_(0),
86 hostRqPsn_(0),
87 hostSqPsn_(0),
88 mrAddr_(0),
89 mrRkey_(0),
90 thread_(nullptr),
91 threadEn_(false),
92 frameCount_(0),
93 byteCount_(0) {
94
95 log_ = rogue::Logging::create("rocev2.Server");
96 memset(hostGid_, 0, 16);
97 memset(fpgaGid_, 0, 16);
98
99 // The destructor does NOT run on a partially-constructed object, so any
100 // throw between here and the end of the body would leak slab_ / mr_ /
101 // cq_ / qp_. Wrap the body in try/catch and call cleanupResources() on
102 // the way out before rethrowing — same effect as a stack of unique_ptr
103 // wrappers but with a single cleanup path.
104 try {
105 // -------------------------------------------------------------------
106 // 1. Allocate slab
107 // RC QPs do not prepend a GRH so each slot is exactly maxPayload_.
108 // posix_memalign accepts any size (aligned_alloc requires the size
109 // to be a multiple of the alignment per C11; with the default
110 // 9000 * 256 slab that constraint does not hold).
111 // -------------------------------------------------------------------
112 bufSize_ = maxPayload_;
113
114 uint64_t slabSize64 = static_cast<uint64_t>(numBufs_) * bufSize_;
115 if (slabSize64 > UINT32_MAX)
116 throw(rogue::GeneralError::create("rocev2::Server::Server",
117 "RX slab too large: %u * %u = %" PRIu64 " exceeds 4 GiB",
118 numBufs_, bufSize_, slabSize64));
119 slabSize_ = static_cast<uint32_t>(slabSize64);
120
121 void* slabPtr = nullptr;
122 if (posix_memalign(&slabPtr, 4096, slabSize_) != 0 || !slabPtr)
123 throw(rogue::GeneralError::create("rocev2::Server::Server",
124 "Failed to allocate RX slab (%u bytes)",
125 slabSize_));
126 slab_ = static_cast<uint8_t*>(slabPtr);
127 memset(slab_, 0, slabSize_);
128
129 // -------------------------------------------------------------------
130 // 2. Register slab as a single MR
131 // -------------------------------------------------------------------
132 mr_ = ibv_reg_mr(pd_, slab_, slabSize_,
133 IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE);
134 if (!mr_)
135 throw(rogue::GeneralError::create("rocev2::Server::Server",
136 "ibv_reg_mr failed"));
137
138 mrAddr_ = reinterpret_cast<uint64_t>(slab_);
139 mrRkey_ = mr_->rkey;
140
141 log_->info("MR: addr=0x%016" PRIx64 " rkey=0x%08x size=%u",
142 mrAddr_, mrRkey_, slabSize_);
143
144 // -------------------------------------------------------------------
145 // 3. Create Completion Queue
146 // -------------------------------------------------------------------
147 cq_ = ibv_create_cq(ctx_,
148 static_cast<int>(numBufs_),
149 nullptr, nullptr, 0);
150 if (!cq_)
151 throw(rogue::GeneralError::create("rocev2::Server::Server",
152 "ibv_create_cq failed"));
153
154 // -------------------------------------------------------------------
155 // 4. Create RC Queue Pair
156 // -------------------------------------------------------------------
157 struct ibv_qp_init_attr qpAttr;
158 memset(&qpAttr, 0, sizeof(qpAttr));
159 qpAttr.qp_type = IBV_QPT_RC;
160 qpAttr.sq_sig_all = 0;
161 qpAttr.send_cq = cq_;
162 qpAttr.recv_cq = cq_;
163 qpAttr.cap.max_recv_wr = numBufs_;
164 qpAttr.cap.max_send_wr = 1;
165 qpAttr.cap.max_recv_sge = 1;
166 qpAttr.cap.max_send_sge = 1;
167
168 qp_ = ibv_create_qp(pd_, &qpAttr);
169 if (!qp_)
170 throw(rogue::GeneralError::create("rocev2::Server::Server",
171 "ibv_create_qp (RC) failed"));
172
173 hostQpn_ = qp_->qp_num;
174
175 // -------------------------------------------------------------------
176 // 5. QP: RESET → INIT
177 // -------------------------------------------------------------------
178 {
179 struct ibv_qp_attr attr;
180 memset(&attr, 0, sizeof(attr));
181 attr.qp_state = IBV_QPS_INIT;
182 attr.pkey_index = 0;
183 attr.port_num = ibPort_;
184 attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE |
185 IBV_ACCESS_REMOTE_READ |
186 IBV_ACCESS_LOCAL_WRITE;
187
188 if (ibv_modify_qp(qp_, &attr,
189 IBV_QP_STATE |
190 IBV_QP_PKEY_INDEX |
191 IBV_QP_PORT |
192 IBV_QP_ACCESS_FLAGS))
193 throw(rogue::GeneralError::create("rocev2::Server::Server",
194 "QP RESET→INIT failed"));
195 }
196
197 // -------------------------------------------------------------------
198 // 6. Read host GID
199 //
200 // The rdma_rxe (Soft-RoCE) kernel driver does NOT validate
201 // gidIndex against the populated range of its GID table —
202 // ibv_query_gid returns rc=0 for any in-range index per the
203 // reported gid_tbl_len (1024 on RXE) and silently writes an
204 // all-zero GID for unpopulated slots. A zero GID passes the
205 // rc==0 check here but cripples the later QP→RTR transition
206 // (dest GID cannot resolve to a peer), producing a cryptic
207 // downstream failure whose trail back to the bad gidIndex is
208 // obscured. Validate the returned GID is non-zero so users
209 // get a clear, actionable error pinned to the gidIndex they
210 // actually passed — valid RoCE GIDs are never all-zero
211 // (IPv4-mapped carries the 0xFFFF marker, IB-native uses an
212 // fe80::/10 or assigned subnet prefix).
213 // -------------------------------------------------------------------
214 union ibv_gid gid;
215 if (ibv_query_gid(ctx_, ibPort_, gidIndex_, &gid))
216 throw(rogue::GeneralError::create("rocev2::Server::Server",
217 "ibv_query_gid failed"));
218 bool zeroGid = true;
219 for (int i = 0; i < 16; ++i) {
220 if (gid.raw[i] != 0) {
221 zeroGid = false;
222 break;
223 }
224 }
225 if (zeroGid)
226 throw(rogue::GeneralError::create("rocev2::Server::Server",
227 "GID query returned all-zero for "
228 "gidIndex=%u on device '%s' "
229 "(likely out-of-range; rdma_rxe "
230 "does not validate gidIndex and "
231 "returns an empty GID for unused "
232 "slots)",
233 gidIndex_,
234 deviceName_.c_str()));
235 memcpy(hostGid_, gid.raw, 16);
236
237 // -------------------------------------------------------------------
238 // 7. Random starting PSNs (seeded per construction to avoid
239 // deterministic sequences across process restarts; RC QP PSN is
240 // expected to be randomized to reduce stale/replay confusion).
241 // -------------------------------------------------------------------
242 std::mt19937 psnRng(std::random_device {}());
243 hostRqPsn_ = psnRng() & 0xFFFFFF;
244 hostSqPsn_ = psnRng() & 0xFFFFFF;
245
246 log_->info("RC QP ready: qpn=0x%06x rqPsn=0x%06x sqPsn=0x%06x",
247 hostQpn_, hostRqPsn_, hostSqPsn_);
248 } catch (...) {
249 cleanupResources();
250 throw;
251 }
252}
253
254// ---------------------------------------------------------------------------
255// cleanupResources — release every ibverbs / heap resource owned by Server,
256// in reverse order of allocation. Idempotent (safe to call from both the
257// failed-construction path and stop()).
258// ---------------------------------------------------------------------------
259void rpr::Server::cleanupResources() {
260 if (qp_) {
261 ibv_destroy_qp(qp_);
262 qp_ = nullptr;
263 }
264 if (cq_) {
265 ibv_destroy_cq(cq_);
266 cq_ = nullptr;
267 }
268 if (mr_) {
269 ibv_dereg_mr(mr_);
270 mr_ = nullptr;
271 }
272 if (slab_) {
273 free(slab_);
274 slab_ = nullptr;
275 }
276}
277
278// ---------------------------------------------------------------------------
279// setFpgaGid
280// ---------------------------------------------------------------------------
281void rpr::Server::setFpgaGid(const std::string& gidBytes) {
282 if (gidBytes.size() != 16)
283 throw(rogue::GeneralError::create("rocev2::Server::setFpgaGid",
284 "GID must be 16 bytes, got %zu",
285 gidBytes.size()));
286 memcpy(fpgaGid_, gidBytes.c_str(), 16);
287 log_->info("FPGA GID stored");
288}
289
290// ---------------------------------------------------------------------------
291// completeConnection — finish handshake and start receive thread
292// ---------------------------------------------------------------------------
293void rpr::Server::completeConnection(uint32_t fpgaQpn, uint32_t fpgaRqPsn,
294 uint32_t pmtu, uint32_t minRnrTimer) {
295 // Single-use: a second call would reassign thread_ and orphan the
296 // original std::thread. Real misuse would also be caught by
297 // ibv_modify_qp rejecting INIT→RTR when the QP is already in RTS,
298 // but guarding here gives a clearer error and prevents the raw
299 // pointer reassignment pattern entirely.
300 if (thread_ != nullptr)
302 "rocev2::Server::completeConnection",
303 "completeConnection already invoked; destroy and recreate "
304 "Server to re-establish the RC connection"));
305
306 // pmtu is blindly static_cast<ibv_mtu>() below; validate the range up
307 // front so a direct C++ caller (bypassing the Python wrapper which
308 // already validates) can't smuggle an undefined enum value into
309 // ibv_modify_qp. Mirrors RoCEv2Server.__init__'s 1..5 check.
310 if (pmtu < 1 || pmtu > 5)
312 "rocev2::Server::completeConnection",
313 "pmtu must be in the range 1..5 "
314 "(1=256 2=512 3=1024 4=2048 5=4096); got %u", pmtu));
315
316 log_->info("completeConnection: fpgaQpn=0x%06x fpgaRqPsn=0x%06x minRnrTimer=%u",
317 fpgaQpn, fpgaRqPsn, minRnrTimer);
318
319 // Pre-post all receive WRs BEFORE moving to RTR so no incoming
320 // RDMA WRITE-with-Immediate finds an empty RQ (which would cause RNR).
321 for (uint32_t i = 0; i < numBufs_; ++i) postRecvWr(i);
322 log_->info("Pre-posted %u recv WRs", numBufs_);
323
324 // QP: INIT → RTR
325 {
326 union ibv_gid dgid;
327 memcpy(dgid.raw, fpgaGid_, 16);
328
329 struct ibv_qp_attr attr;
330 memset(&attr, 0, sizeof(attr));
331 attr.qp_state = IBV_QPS_RTR;
332 attr.path_mtu = static_cast<ibv_mtu>(pmtu);
333 attr.dest_qp_num = fpgaQpn;
334 attr.rq_psn = fpgaRqPsn;
335 attr.max_dest_rd_atomic = 16;
336 attr.min_rnr_timer = minRnrTimer;
337 attr.ah_attr.is_global = 1;
338 attr.ah_attr.grh.dgid = dgid;
339 attr.ah_attr.grh.sgid_index = gidIndex_;
340 attr.ah_attr.grh.hop_limit = 64;
341 attr.ah_attr.port_num = ibPort_;
342 attr.ah_attr.sl = 0;
343
344 if (ibv_modify_qp(qp_, &attr,
345 IBV_QP_STATE |
346 IBV_QP_AV |
347 IBV_QP_PATH_MTU |
348 IBV_QP_DEST_QPN |
349 IBV_QP_RQ_PSN |
350 IBV_QP_MAX_DEST_RD_ATOMIC |
351 IBV_QP_MIN_RNR_TIMER))
352 throw(rogue::GeneralError::create("rocev2::Server::completeConnection",
353 "QP INIT→RTR failed"));
354 }
355
356 log_->info("QP → RTR (minRnrTimer=%u)", minRnrTimer);
357
358 // QP: RTR → RTS
359 {
360 struct ibv_qp_attr attr;
361 memset(&attr, 0, sizeof(attr));
362 attr.qp_state = IBV_QPS_RTS;
363 attr.sq_psn = hostSqPsn_;
364 attr.timeout = 14;
365 attr.retry_cnt = 3;
366 attr.rnr_retry = 3;
367 attr.max_rd_atomic = 16;
368
369 if (ibv_modify_qp(qp_, &attr,
370 IBV_QP_STATE |
371 IBV_QP_SQ_PSN |
372 IBV_QP_TIMEOUT |
373 IBV_QP_RETRY_CNT |
374 IBV_QP_RNR_RETRY |
375 IBV_QP_MAX_QP_RD_ATOMIC))
376 throw(rogue::GeneralError::create("rocev2::Server::completeConnection",
377 "QP RTR→RTS failed"));
378 }
379
380 log_->info("QP → RTS — ready to receive RDMA WRITEs");
381
382 // Start receive thread
383 std::shared_ptr<int> scopePtr = std::make_shared<int>(0);
384 threadEn_.store(true);
385 thread_ = new std::thread(&rpr::Server::runThread, this,
386 std::weak_ptr<int>(scopePtr));
387
388#ifndef __MACH__
389 pthread_setname_np(thread_->native_handle(), "RoCEv2Server");
390#endif
391}
392
393// ---------------------------------------------------------------------------
394// getGid
395// ---------------------------------------------------------------------------
396std::string rpr::Server::getGid() const {
397 std::ostringstream oss;
398 for (int i = 0; i < 16; i += 2) {
399 if (i) oss << ':';
400 oss << std::hex << std::setfill('0')
401 << std::setw(2) << static_cast<int>(hostGid_[i])
402 << std::setw(2) << static_cast<int>(hostGid_[i+1]);
403 }
404 return oss.str();
405}
406
407// ---------------------------------------------------------------------------
408// postRecvWr — post a receive WR for slot `slot`
409// wr_id == slot index so no lookup is needed on completion
410// ---------------------------------------------------------------------------
411void rpr::Server::postRecvWr(uint32_t slot) {
412 // Defensive: slot indexes into slab_; a corrupted wr_id (from the CQ)
413 // or meta (from retBuffer) must not produce an out-of-bounds slab
414 // pointer. Normal control flow keeps slot < numBufs_ because we set
415 // wr_id = slot at post time and encode slot in meta at createBuffer
416 // time, but the check is cheap and catches any future regression.
417 if (slot >= numBufs_)
418 throw(rogue::GeneralError::create("rocev2::Server::postRecvWr",
419 "slot=%u out of range (numBufs=%u)",
420 slot, numBufs_));
421
422 uint8_t* bufStart = slab_ + (static_cast<uint64_t>(slot) * bufSize_);
423
424 struct ibv_sge sge;
425 memset(&sge, 0, sizeof(sge));
426 sge.addr = reinterpret_cast<uint64_t>(bufStart);
427 sge.length = bufSize_;
428 sge.lkey = mr_->lkey;
429
430 struct ibv_recv_wr wr;
431 memset(&wr, 0, sizeof(wr));
432 wr.wr_id = static_cast<uint64_t>(slot);
433 wr.sg_list = &sge;
434 wr.num_sge = 1;
435 wr.next = nullptr;
436
437 struct ibv_recv_wr* bad = nullptr;
438 if (ibv_post_recv(qp_, &wr, &bad))
439 throw(rogue::GeneralError::create("rocev2::Server::postRecvWr",
440 "ibv_post_recv failed (slot=%u)", slot));
441}
442
443// ---------------------------------------------------------------------------
444// retBuffer — zero-copy hook
445//
446// Called by Buffer::~Buffer() when the last FramePtr holding this slot is
447// released by downstream. We re-post the slot to the QP so the FPGA can
448// write into it again.
449//
450// meta lower 24 bits = slot index (set in createBuffer() call in runThread)
451// ---------------------------------------------------------------------------
452void rpr::Server::retBuffer(uint8_t* data, uint32_t meta, uint32_t rawSize) {
453 uint32_t slot = meta & 0x00FFFFFF;
454
455 log_->debug("retBuffer: re-posting slot=%u", slot);
456
457 if (threadEn_.load() && qp_) {
458 try {
459 postRecvWr(slot);
460 } catch (...) {
461 // Swallow errors during shutdown
462 }
463 }
464
465 decCounter(rawSize);
466}
467
468// ---------------------------------------------------------------------------
469// runThread — CQ polling loop (zero-copy)
470// ---------------------------------------------------------------------------
471void rpr::Server::runThread(std::weak_ptr<int> lockPtr) {
472 while (!lockPtr.expired()) continue;
473
474 log_->logThreadId();
475 log_->info("RoCEv2 receive thread started");
476
477 rogue::GilRelease noGil; // Release GIL for the entire thread;
478 // sendFrame() re-acquires via ScopedGil when
479 // calling Python slaves.
480
481 struct ibv_wc wc;
482
483 // The poll loop body is wrapped in try/catch so that an ibverbs failure
484 // (postRecvWr throws rogue::GeneralError on ibv_post_recv failure)
485 // shuts the thread down cleanly instead of escaping the thread entry
486 // point and triggering std::terminate.
487 try {
488 while (threadEn_.load()) {
489 int n = ibv_poll_cq(cq_, 1, &wc);
490 if (n == 0) {
491 std::this_thread::sleep_for(std::chrono::microseconds(100));
492 continue;
493 }
494 if (n < 0) {
495 log_->warning("ibv_poll_cq error");
496 continue;
497 }
498
499 uint32_t slot = static_cast<uint32_t>(wc.wr_id);
500
501 // Defensive: every posted WR sets wr_id = slot with slot <
502 // numBufs_; a corrupted wr_id must not be dereferenced as a
503 // slab offset at line `slab_ + slot * bufSize_` below. We
504 // cannot safely re-post either (the real slot is unknown),
505 // so drop the completion and keep polling.
506 if (slot >= numBufs_) {
507 log_->warning("CQ returned out-of-range wr_id=%" PRIu64
508 " (numBufs=%u); discarding",
509 static_cast<uint64_t>(wc.wr_id), numBufs_);
510 continue;
511 }
512
513 if (wc.status != IBV_WC_SUCCESS) {
514 log_->warning("CQ error: %s (slot=%u)",
515 ibv_wc_status_str(wc.status), slot);
516
517 if (wc.status == IBV_WC_WR_FLUSH_ERR) {
518 // QP transitioned to ERROR; every remaining posted
519 // WR flushes with this status. Do NOT re-post - stop the
520 // thread gracefully.
521 log_->error("QP in ERROR state (WR_FLUSH_ERR); exiting CQ poll thread");
522 threadEn_.store(false);
523 break;
524 }
525
526 postRecvWr(slot);
527 continue;
528 }
529
530 if (wc.opcode != IBV_WC_RECV_RDMA_WITH_IMM) {
531 log_->warning("Unexpected opcode %d (slot=%u), re-posting",
532 wc.opcode, slot);
533 postRecvWr(slot);
534 continue;
535 }
536
537 // Decode immediate value: bits [7:0] = channel id
538 uint8_t channel = static_cast<uint8_t>(wc.imm_data & 0xFF);
539 uint32_t payloadLen = wc.byte_len;
540
541 if (payloadLen == 0 || payloadLen > bufSize_) {
542 log_->warning("Bad payload len=%u (slot=%u), re-posting",
543 payloadLen, slot);
544 postRecvWr(slot);
545 continue;
546 }
547
548 // Zero-copy: wrap the slab slot directly as a rogue Buffer.
549 // retBuffer() re-posts the slot when downstream releases it.
550 uint8_t* slotPtr = slab_ + (static_cast<uint64_t>(slot) * bufSize_);
551
552 ris::BufferPtr buff = createBuffer(slotPtr,
553 slot & 0x00FFFFFF,
554 payloadLen,
555 bufSize_);
556 buff->setPayload(payloadLen);
557
558 ris::FramePtr frame = ris::Frame::create();
559 frame->appendBuffer(buff);
560 frame->setChannel(channel);
561 frame->setFirstUser(SsiSof);
562 frame->setLastUser(0);
563
564 log_->debug("RX slot=%u channel=%u len=%u", slot, channel, payloadLen);
565
566 sendFrame(frame);
567
568 frameCount_.fetch_add(1, std::memory_order_relaxed);
569 byteCount_.fetch_add(payloadLen, std::memory_order_relaxed);
570 }
571 } catch (const rogue::GeneralError& e) {
572 log_->error("RoCEv2 receive thread exiting on ibverbs error: %s", e.what());
573 threadEn_.store(false);
574 } catch (const std::exception& e) {
575 log_->error("RoCEv2 receive thread exiting on exception: %s", e.what());
576 threadEn_.store(false);
577 } catch (...) {
578 log_->error("RoCEv2 receive thread exiting on unknown exception");
579 threadEn_.store(false);
580 }
581
582 log_->info("RoCEv2 receive thread stopped");
583}
584
585// ---------------------------------------------------------------------------
586// acceptFrame — TX not supported. The parameter is required by the
587// stream::Slave contract but intentionally unused; name omitted to silence
588// -Wunused-parameter without a `(void)frame;` cast in the body.
589// ---------------------------------------------------------------------------
590void rpr::Server::acceptFrame(ris::FramePtr /*frame*/) {
591 log_->warning("RoCEv2 Server::acceptFrame: TX not supported, dropping");
592}
593
594// ---------------------------------------------------------------------------
595// stop / destructor
596// ---------------------------------------------------------------------------
597void rpr::Server::stop() {
598 // Signal the thread to exit if it is still running. Always join /
599 // delete thread_ when it is non-null: runThread() may have already
600 // cleared threadEn_ itself (e.g. on IBV_WC_WR_FLUSH_ERR or a caught
601 // exception), which would otherwise leave thread_ joinable and cause
602 // ~std::thread to terminate the process.
603 threadEn_.store(false);
604 if (thread_) {
605 if (thread_->joinable()) thread_->join();
606 delete thread_;
607 thread_ = nullptr;
608 }
609 cleanupResources();
610}
611
612rpr::Server::~Server() { this->stop(); }
613
614// ---------------------------------------------------------------------------
615// Python bindings
616// ---------------------------------------------------------------------------
617void rpr::Server::setup_python() {
618#ifndef NO_PYTHON
619 bp::class_<rpr::Server,
621 bp::bases<rpr::Core, ris::Master, ris::Slave>,
622 boost::noncopyable>(
623 "Server",
624 bp::init<std::string, uint8_t, uint8_t, uint32_t, uint32_t>(
625 (bp::arg("deviceName"),
626 bp::arg("ibPort") = 1,
627 bp::arg("gidIndex") = 0,
628 bp::arg("maxPayload") = rpr::DefaultMaxPayload,
629 bp::arg("rxQueueDepth") = rpr::DefaultRxQueueDepth)))
630 .def("create", &rpr::Server::create)
631 .staticmethod("create")
632 .def("setFpgaGid", &rpr::Server::setFpgaGid)
633 .def("completeConnection", &rpr::Server::completeConnection,
634 (bp::arg("fpgaQpn"),
635 bp::arg("fpgaRqPsn"),
636 bp::arg("pmtu") = 5,
637 bp::arg("minRnrTimer") = 1))
638 .def("getQpn", &rpr::Server::getQpn)
639 .def("getGid", &rpr::Server::getGid)
640 .def("getRqPsn", &rpr::Server::getRqPsn)
641 .def("getSqPsn", &rpr::Server::getSqPsn)
642 .def("getMrAddr", &rpr::Server::getMrAddr)
643 .def("getMrRkey", &rpr::Server::getMrRkey)
644 .def("getFrameCount", &rpr::Server::getFrameCount)
645 .def("getByteCount", &rpr::Server::getByteCount)
646 .def("stop", &rpr::Server::stop);
647
648 bp::implicitly_convertible<rpr::ServerPtr, rpr::CorePtr>();
649 bp::implicitly_convertible<rpr::ServerPtr, ris::MasterPtr>();
650 bp::implicitly_convertible<rpr::ServerPtr, ris::SlavePtr>();
651#endif
652}
Generic Rogue exception type.
char const * what() const
Returns exception text for standard exception handling.
static GeneralError create(std::string src, const char *fmt,...)
Creates a formatted error instance.
RAII helper that releases the Python GIL for a scope.
Definition GilRelease.h:36
static std::shared_ptr< rogue::Logging > create(const std::string &name, bool quiet=false)
Creates a logger instance.
Definition Logging.cpp:95
struct ibv_pd * pd_
Definition Core.h:47
struct ibv_context * ctx_
Definition Core.h:46
uint32_t maxPayload() const
Definition Core.h:65
std::shared_ptr< rogue::interfaces::stream::Buffer > BufferPtr
Shared pointer alias for Buffer.
Definition Buffer.h:270
std::shared_ptr< rogue::interfaces::stream::Frame > FramePtr
Shared pointer alias for Frame.
Definition Frame.h:549
std::shared_ptr< rogue::protocols::rocev2::Server > ServerPtr
Definition Server.h:150
static const uint32_t DefaultMaxPayload
Definition Core.h:40
static const uint32_t DefaultRxQueueDepth
Definition Core.h:35
static const uint8_t SsiSof
Definition Server.cpp:53