diff --git a/Makefile b/Makefile index a6923cf..ec1ca52 100644 --- a/Makefile +++ b/Makefile @@ -12,8 +12,8 @@ PROJECT_NAME = libinfinity ################################################## -CC = g++ -CC_FLAGS = -O3 -std=c++0x +CC = g++ +CC_FLAGS = -O3 -std=c++0x -D_RDMA_USE_ODP LD_FLAGS = -linfinity -libverbs ################################################## diff --git a/README.md b/README.md index c41feee..680acad 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ Infinity is a simple, powerful, object-oriented abstraction of ibVerbs. The libr ## Installation +### Note + +**If you would like to build this library without On-Demand-Paging for RDMA (e.g., your device does not support it), then remove the `-D_RDMA_USE_ODP` flag from `CC_FLAGS` in the `Makefile`.** + Installing ''ibVerbs'' is a prerequisite before building Infinity. The output is located in ''release/libinfinity.a''. ```sh diff --git a/src/infinity/core/Context.cpp b/src/infinity/core/Context.cpp index 78e1283..0ab68f5 100644 --- a/src/infinity/core/Context.cpp +++ b/src/infinity/core/Context.cpp @@ -71,6 +71,18 @@ Context::Context(uint16_t device, uint16_t devicePort) { defaultRequestToken = new infinity::requests::RequestToken(this); defaultAtomic = new infinity::memory::Atomic(this); +#ifdef _RDMA_USE_ODP + // Check if On-Demand-Paging (ODP) is supported by the device + ibv_device_attr_ex da; + INFINITY_ASSERT(ibv_query_device_ex(this->ibvContext, NULL, &da) == 0, "[INFINITY][CORE][CONTEXT] Failed to query device for extended device properties.\n"); + INFINITY_ASSERT(da.odp_caps.general_caps & IBV_ODP_SUPPORT, "[INFINITY][CORE][CONTEXT] ODP is not supported.\n"); + INFINITY_ASSERT(da.odp_caps.general_caps & IBV_ODP_SUPPORT_IMPLICIT, "[INFINITY][CORE][CONTEXT] ODP implicit is not supported.\n"); + INFINITY_ASSERT(da.odp_caps.per_transport_caps.rc_odp_caps & IBV_ODP_SUPPORT_READ, "[INFINITY][CORE][CONTEXT] ODP for reads is not supported.\n"); + INFINITY_ASSERT(da.odp_caps.per_transport_caps.rc_odp_caps & IBV_ODP_SUPPORT_RECV, "[INFINITY][CORE][CONTEXT] ODP for receives is not supported.\n"); + INFINITY_ASSERT(da.odp_caps.per_transport_caps.rc_odp_caps & IBV_ODP_SUPPORT_WRITE, "[INFINITY][CORE][CONTEXT] ODP for writes is not supported.\n"); + INFINITY_ASSERT(da.odp_caps.per_transport_caps.rc_odp_caps & IBV_ODP_SUPPORT_SEND, "[INFINITY][CORE][CONTEXT] ODP for sends is not supported.\n"); +#endif // _RDMA_USE_ODP + } Context::~Context() { diff --git a/src/infinity/memory/Buffer.cpp b/src/infinity/memory/Buffer.cpp index c6cc5a1..0a75eda 100644 --- a/src/infinity/memory/Buffer.cpp +++ b/src/infinity/memory/Buffer.cpp @@ -30,8 +30,14 @@ Buffer::Buffer(infinity::core::Context* context, uint64_t sizeInBytes) { memset(this->data, 0, sizeInBytes); +#ifdef _RDMA_USE_ODP + this->ibvMemoryRegion = ibv_reg_mr(this->context->getProtectionDomain(), NULL, SIZE_MAX, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_ON_DEMAND); +#else this->ibvMemoryRegion = ibv_reg_mr(this->context->getProtectionDomain(), this->data, this->sizeInBytes, IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ); +#endif // _RDMA_USE_ODP + INFINITY_ASSERT(this->ibvMemoryRegion != NULL, "[INFINITY][MEMORY][BUFFER] Registration failed.\n"); this->memoryAllocated = true; @@ -60,8 +66,15 @@ Buffer::Buffer(infinity::core::Context *context, void *memory, uint64_t sizeInBy this->memoryRegionType = RegionType::BUFFER; this->data = memory; + +#ifdef _RDMA_USE_ODP + this->ibvMemoryRegion = ibv_reg_mr(this->context->getProtectionDomain(), NULL, SIZE_MAX, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_ON_DEMAND); +#else this->ibvMemoryRegion = ibv_reg_mr(this->context->getProtectionDomain(), this->data, this->sizeInBytes, IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ); +#endif // _RDMA_USE_ODP + INFINITY_ASSERT(this->ibvMemoryRegion != NULL, "[INFINITY][MEMORY][BUFFER] Registration failed.\n"); this->memoryAllocated = false; @@ -84,6 +97,16 @@ void* Buffer::getData() { return reinterpret_cast(this->getAddress()); } +void Buffer::setData(void *data, uint64_t sizeInBytes) { + if (this->memoryAllocated) { + free(this->data); + } + + this->data = data; + this->sizeInBytes = sizeInBytes; + this->memoryAllocated = false; +} + void Buffer::resize(uint64_t newSize, void* newData) { void *oldData = this->data; @@ -100,8 +123,14 @@ void Buffer::resize(uint64_t newSize, void* newData) { if (memoryRegistered) { ibv_dereg_mr(this->ibvMemoryRegion); + + // When using ODP, nothing needs to be done since we don't register specific addresses anyway. + // So re-assigning a new buffer and new size is a no-op in the ODP case in terms of registering. +#ifndef _RDMA_USE_ODP this->ibvMemoryRegion = ibv_reg_mr(this->context->getProtectionDomain(), newData, newSize, IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ); +#endif // _RDMA_USE_ODP + this->data = newData; this->sizeInBytes = newSize; } else { diff --git a/src/infinity/memory/Buffer.h b/src/infinity/memory/Buffer.h index 28b5e49..79e868e 100644 --- a/src/infinity/memory/Buffer.h +++ b/src/infinity/memory/Buffer.h @@ -28,6 +28,7 @@ class Buffer : public Region { public: void * getData(); + void setData(void *data, uint64_t sizeInBytes); void resize(uint64_t newSize, void *newData = NULL); protected: diff --git a/src/infinity/memory/RegisteredMemory.cpp b/src/infinity/memory/RegisteredMemory.cpp index e87f3e0..d5c6c0b 100644 --- a/src/infinity/memory/RegisteredMemory.cpp +++ b/src/infinity/memory/RegisteredMemory.cpp @@ -28,8 +28,14 @@ RegisteredMemory::RegisteredMemory(infinity::core::Context* context, uint64_t si memset(this->data, 0, sizeInBytes); +#ifdef _RDMA_USE_ODP + this->ibvMemoryRegion = ibv_reg_mr(this->context->getProtectionDomain(), NULL, SIZE_MAX, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_ON_DEMAND); +#else this->ibvMemoryRegion = ibv_reg_mr(this->context->getProtectionDomain(), this->data, this->sizeInBytes, IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ); +#endif // _RDMA_USE_ODP + INFINITY_ASSERT(this->ibvMemoryRegion != NULL, "[INFINITY][MEMORY][REGISTERED] Registration failed.\n"); } @@ -41,8 +47,14 @@ RegisteredMemory::RegisteredMemory(infinity::core::Context* context, void *data, this->data = data; +#ifdef _RDMA_USE_ODP + this->ibvMemoryRegion = ibv_reg_mr(this->context->getProtectionDomain(), NULL, SIZE_MAX, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_ON_DEMAND); +#else this->ibvMemoryRegion = ibv_reg_mr(this->context->getProtectionDomain(), this->data, this->sizeInBytes, IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ); +#endif // _RDMA_USE_ODP + INFINITY_ASSERT(this->ibvMemoryRegion != NULL, "[INFINITY][MEMORY][REGISTERED] Registration failed.\n"); } diff --git a/src/infinity/queues/QueuePair.cpp b/src/infinity/queues/QueuePair.cpp index c8fda8f..4fb12b5 100644 --- a/src/infinity/queues/QueuePair.cpp +++ b/src/infinity/queues/QueuePair.cpp @@ -38,6 +38,28 @@ int OperationFlags::ibvFlags() { QueuePair::QueuePair(infinity::core::Context* context) : context(context) { +#ifdef _RDMA_USE_ODP + ibv_qp_init_attr_ex qpInitAttributes; + memset(&qpInitAttributes, 0, sizeof(qpInitAttributes)); + + qpInitAttributes.send_cq = context->getSendCompletionQueue(); + qpInitAttributes.recv_cq = context->getReceiveCompletionQueue(); + qpInitAttributes.srq = context->getSharedReceiveQueue(); + qpInitAttributes.cap.max_send_wr = MAX(infinity::core::Configuration::SEND_COMPLETION_QUEUE_LENGTH, 1); + qpInitAttributes.cap.max_send_sge = infinity::core::Configuration::MAX_NUMBER_OF_SGE_ELEMENTS; + qpInitAttributes.cap.max_recv_wr = MAX(infinity::core::Configuration::RECV_COMPLETION_QUEUE_LENGTH, 1); + qpInitAttributes.cap.max_recv_sge = infinity::core::Configuration::MAX_NUMBER_OF_SGE_ELEMENTS; + qpInitAttributes.qp_type = IBV_QPT_RC; + qpInitAttributes.sq_sig_all = 0; + qpInitAttributes.pd = context->getProtectionDomain(); + qpInitAttributes.comp_mask = IBV_QP_INIT_ATTR_PD | IBV_QP_INIT_ATTR_SEND_OPS_FLAGS; + qpInitAttributes.send_ops_flags = IBV_QP_EX_WITH_SEND; + + this->ibvQueuePair = ibv_create_qp_ex(context->getInfiniBandContext(), &qpInitAttributes); + INFINITY_ASSERT(this->ibvQueuePair != NULL, "[INFINITY][QUEUES][QUEUEPAIR] Cannot create queue pair.\n"); + + unsigned int qp_access_flags = 0; +#else ibv_qp_init_attr qpInitAttributes; memset(&qpInitAttributes, 0, sizeof(qpInitAttributes)); @@ -54,13 +76,16 @@ QueuePair::QueuePair(infinity::core::Context* context) : this->ibvQueuePair = ibv_create_qp(context->getProtectionDomain(), &(qpInitAttributes)); INFINITY_ASSERT(this->ibvQueuePair != NULL, "[INFINITY][QUEUES][QUEUEPAIR] Cannot create queue pair.\n"); + unsigned int qp_access_flags = IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_ATOMIC; +#endif // _RDMA_USE_ODP + ibv_qp_attr qpAttributes; memset(&qpAttributes, 0, sizeof(qpAttributes)); qpAttributes.qp_state = IBV_QPS_INIT; qpAttributes.pkey_index = 0; qpAttributes.port_num = context->getDevicePort(); - qpAttributes.qp_access_flags = IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_ATOMIC; + qpAttributes.qp_access_flags = qp_access_flags; int32_t returnValue = ibv_modify_qp(this->ibvQueuePair, &(qpAttributes), IBV_QP_STATE | IBV_QP_PORT | IBV_QP_ACCESS_FLAGS | IBV_QP_PKEY_INDEX); diff --git a/src/infinity/queues/QueuePairFactory.cpp b/src/infinity/queues/QueuePairFactory.cpp index ddd3c13..f70225b 100644 --- a/src/infinity/queues/QueuePairFactory.cpp +++ b/src/infinity/queues/QueuePairFactory.cpp @@ -67,6 +67,7 @@ void QueuePairFactory::bindToPort(uint16_t port) { char *ipAddressOfDevice = infinity::utils::Address::getIpAddressOfInterface(infinity::core::Configuration::DEFAULT_IB_DEVICE); INFINITY_DEBUG("[INFINITY][QUEUES][FACTORY] Accepting connections on IP address %s and port %d.\n", ipAddressOfDevice, port); + INFINITY_DEBUG("[INFINITY][QUEUES][FACTORY] Accepting connections on interface %s, IP address %s and port %d.\n", interfaceNameToQuery, ipAddressOfDevice, port); free(ipAddressOfDevice); }