Skip to content

Commit

Permalink
Project import generated by Copybara.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 367997251
  • Loading branch information
RDMA authored and swoloschek-goog committed Apr 12, 2021
1 parent 63b9725 commit 3a27bfd
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 10 deletions.
27 changes: 22 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,20 @@ to fix overly-specificified tests are encouraged.

## Installation

Prior to building the ibverb user space libraries must be installed.

sudo apt install libibverbs libibverbs-dev
rdma-unit-test has been built/tested on CentOS 8.3.2011 using a Mellonox
ConnectX-4 Dual port 25Gbe adapter. Installation requirements may vary
depending upon the distro used.
CentOS installation uses the standard Server configuration with the following
options;
* Infiniband support
* Development Tools

Additional requirements;
* ivberbs development libraries; sudo yum install libibverbs-devel
* bazel build tool; instructions [here](https://docs.bazel.build/versions/master/install-redhat.html)

The user space libraries are supported and packaged [here](https://github.com/linux-rdma/rdma-core)

rdma-unit-test also requires [nl3](https://www.infradead.org/~tgr/libnl/).

## Introspection

Introspection is used to selectively enable tests depending on hardware
Expand All @@ -41,3 +47,14 @@ specification. Adding introspection support for a new NIC requires 2 changes:

1. Extend NicIntrospection (ex. introspection\_rxe.h)
2. Update gunit\_main.cc to register the new introspection.

## Running
Some ibverb libraries require root priviledges when creating verb queue pairs.
If this is the case the rdma-unit-tests must run as root.

## Device Support
rdma-unit-test has been tested on the following adapters;
* Mellonox ConnectX-3
* Mellonox ConnectX-4
* SoftROCE (limited support_

4 changes: 4 additions & 0 deletions cases/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ cc_test(
":basic_fixture",
":gunit_main",
":status_matchers",
"//public:introspection",
"//public:rdma-memblock",
"//public:util",
"@com_google_absl//absl/status",
Expand Down Expand Up @@ -103,6 +104,7 @@ cc_test(
":basic_fixture",
":gunit_main",
":status_matchers",
"//public:introspection",
"//public:rdma-memblock",
"//public:verbs_helper_suite",
"@com_glog_glog//:glog",
Expand Down Expand Up @@ -157,6 +159,7 @@ cc_test(
":basic_fixture",
":gunit_main",
":status_matchers",
"//public:introspection",
"//public:rdma-memblock",
"//public:util",
"//public:verbs_helper_suite",
Expand Down Expand Up @@ -310,6 +313,7 @@ cc_library(
":basic_fixture",
":status_matchers",
"//public:flags",
"//public:introspection",
"//public:rdma-memblock",
"//public:util",
"//public:verbs_helper_suite",
Expand Down
2 changes: 2 additions & 0 deletions cases/access_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "infiniband/verbs.h"
#include "cases/basic_fixture.h"
#include "cases/status_matchers.h"
#include "public/introspection.h"
#include "public/rdma-memblock.h"
#include "public/util.h"

Expand Down Expand Up @@ -151,6 +152,7 @@ class AccessTest : public BasicFixture,

void AttemptMwAtomic(BasicSetup setup, int src_mr_access, int dst_mr_access,
int dst_mw_access, ibv_wc_status expected) {
if (!Introspection().SupportsRcRemoteMwAtomic()) GTEST_SKIP();
ibv_mr* src_mr = ibv_.RegMr(setup.pd, setup.src_buffer, src_mr_access);
ibv_mr* dst_mr = ibv_.RegMr(setup.pd, setup.dst_buffer, dst_mr_access);
auto [src_qp, dst_qp] = CreateNewConnectedQpPair(setup);
Expand Down
2 changes: 2 additions & 0 deletions cases/cq_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "infiniband/verbs.h"
#include "cases/basic_fixture.h"
#include "cases/status_matchers.h"
#include "public/introspection.h"
#include "public/rdma-memblock.h"
#include "public/verbs_helper_suite.h"

Expand Down Expand Up @@ -467,6 +468,7 @@ TEST_F(CQAdvancedTest, RecvCqOverflow) {

// 2 CQs posting recv completions to a single completion queue.
TEST_F(CQAdvancedTest, RecvSharedCq) {
if (!Introspection().SupportsMultipleOutstandingRecvRequests()) GTEST_SKIP();
ASSERT_OK_AND_ASSIGN(BasicSetup setup, CreateBasicSetup());
static constexpr int kQueueCount = 2;
ASSERT_OK(CreateTestQps(setup, kQueueCount));
Expand Down
113 changes: 112 additions & 1 deletion cases/loopback_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "infiniband/verbs.h"
#include "cases/basic_fixture.h"
#include "cases/status_matchers.h"
#include "public/introspection.h"
#include "public/rdma-memblock.h"
#include "public/util.h"
#include "public/verbs_helper_suite.h"
Expand Down Expand Up @@ -627,6 +628,29 @@ TEST_F(LoopbackRcQpTest, SendWithInvalidateWrongQp) {

}

TEST_F(LoopbackRcQpTest, SendWithTooSmallRecv) {
// Recv buffer is to small to fit the whole buffer.
auto client_pair_or = CreateConnectedClientsPair();
ASSERT_OK(client_pair_or);
auto [local, remote] = client_pair_or.value();
ibv_sge sge = verbs_util::CreateSge(remote.buffer.span(), remote.mr);
const uint32_t kRecvLength = local.buffer.span().size() - 1;
sge.length = kRecvLength;
ibv_recv_wr recv = verbs_util::CreateRecvWr(/*wr_id=*/0, &sge, /*num_sge=*/1);
verbs_util::PostRecv(remote.qp, recv);

ibv_sge lsge = verbs_util::CreateSge(local.buffer.span(), local.mr);
ibv_send_wr send =
verbs_util::CreateSendWr(/*wr_id=*/1, &lsge, /*num_sge=*/1);
verbs_util::PostSend(local.qp, send);
ibv_wc completion = verbs_util::WaitForCompletion(local.cq).value();
ASSERT_EQ(IBV_WC_REM_INV_REQ_ERR, completion.status);
ASSERT_EQ(local.qp->qp_num, completion.qp_num);
ASSERT_EQ(1, completion.wr_id);
ASSERT_EQ(IBV_QPS_ERR, verbs_util::GetQpState(local.qp));
ASSERT_EQ(IBV_QPS_ERR, verbs_util::GetQpState(remote.qp));
}

TEST_F(LoopbackRcQpTest, BadRecvAddr) {
auto client_pair_or = CreateConnectedClientsPair();
ASSERT_OK(client_pair_or);
Expand Down Expand Up @@ -705,7 +729,8 @@ TEST_F(LoopbackRcQpTest, BadRecvLength) {
EXPECT_EQ(remote.qp->qp_num, completion2.qp_num);
EXPECT_EQ(1, completion.wr_id);
EXPECT_EQ(0, completion2.wr_id);
if (Introspection().CorrectlyReportsMemoryRegionErrors()) {
if (Introspection().CorrectlyReportsMemoryRegionErrors() &&
Introspection().CorrectlyReportsInvalidRecvLengthErrors()) {
EXPECT_EQ(IBV_WC_REM_OP_ERR, completion.status);
EXPECT_EQ(IBV_WC_LOC_PROT_ERR, completion2.status);
} else {
Expand Down Expand Up @@ -1275,6 +1300,63 @@ TEST_F(LoopbackRcQpTest, FetchAddNoOp) {
EXPECT_EQ(*(reinterpret_cast<uint64_t*>(local.atomic_buffer.data())), 2);
}

TEST_F(LoopbackRcQpTest, FetchAddSmallSge) {
auto client_pair_or = CreateConnectedClientsPair();
ASSERT_OK(client_pair_or);
auto [local, remote] = client_pair_or.value();
// The local SGE will be used to store the value before the update.
ibv_sge sge = verbs_util::CreateSge(local.atomic_buffer, local.mr);
sge.length = 7;
ibv_send_wr fetch_add = verbs_util::CreateFetchAddWr(
/*wr_id=*/1, &sge, /*num_sge=*/1, remote.atomic_buffer.data(),
remote.mr->rkey, 0);
verbs_util::PostSend(local.qp, fetch_add);
ibv_wc completion = verbs_util::WaitForCompletion(local.cq).value();
EXPECT_EQ(local.qp->qp_num, completion.qp_num);
EXPECT_EQ(1, completion.wr_id);
EXPECT_EQ(IBV_WC_LOC_LEN_ERR, completion.status);
}

TEST_F(LoopbackRcQpTest, FetchAddLargeSge) {
auto client_pair_or = CreateConnectedClientsPair();
ASSERT_OK(client_pair_or);
auto [local, remote] = client_pair_or.value();
// The local SGE will be used to store the value before the update.
ibv_sge sge = verbs_util::CreateSge(local.atomic_buffer, local.mr);
sge.length = 9;
ibv_send_wr fetch_add = verbs_util::CreateFetchAddWr(
/*wr_id=*/1, &sge, /*num_sge=*/1, remote.atomic_buffer.data(),
remote.mr->rkey, 0);
verbs_util::PostSend(local.qp, fetch_add);
ibv_wc completion = verbs_util::WaitForCompletion(local.cq).value();
EXPECT_EQ(local.qp->qp_num, completion.qp_num);
EXPECT_EQ(1, completion.wr_id);
EXPECT_EQ(IBV_WC_LOC_LEN_ERR, completion.status);
}

TEST_F(LoopbackRcQpTest, FetchAddSplitSgl) {
auto client_pair_or = CreateConnectedClientsPair();
ASSERT_OK(client_pair_or);
auto [local, remote] = client_pair_or.value();
// The local SGE will be used to store the value before the update.
ibv_sge sge = verbs_util::CreateSge(local.atomic_buffer, local.mr);
ibv_sge sgl[2];
sgl[0].addr = sge.addr;
sgl[0].length = 4;
sgl[0].lkey = sge.lkey;
sgl[1].addr = sge.addr + 8;
sgl[1].length = 4;
sgl[1].lkey = sge.lkey;
ibv_send_wr fetch_add = verbs_util::CreateFetchAddWr(
/*wr_id=*/1, sgl, /*num_sge=*/2, remote.atomic_buffer.data(),
remote.mr->rkey, 0);
verbs_util::PostSend(local.qp, fetch_add);
ibv_wc completion = verbs_util::WaitForCompletion(local.cq).value();
EXPECT_EQ(local.qp->qp_num, completion.qp_num);
EXPECT_EQ(1, completion.wr_id);
EXPECT_EQ(IBV_WC_REM_ACCESS_ERR, completion.status);
}

TEST_F(LoopbackRcQpTest, UnsignaledFetchAdd) {
auto client_pair_or = CreateConnectedClientsPair();
ASSERT_OK(client_pair_or);
Expand Down Expand Up @@ -2142,6 +2224,35 @@ TEST_F(LoopbackUdQpTest, SendRnr) {
EXPECT_EQ(1, completion.wr_id);
}

TEST_F(LoopbackUdQpTest, SendWithTooSmallRecv) {
constexpr int kPayloadLength = 1000; // Sub-MTU length for UD.
auto client_pair_or = CreateConnectedClientsPair();
ASSERT_OK(client_pair_or);
auto [local, remote] = client_pair_or.value();
const uint32_t recv_length = local.buffer.span().size() / 2;
ibv_sge rsge = verbs_util::CreateSge(remote.buffer.span(), remote.mr);
rsge.length = recv_length + sizeof(ibv_grh);
// Recv buffer is to small to fit the whole buffer.
rsge.length -= 1;
ibv_recv_wr recv =
verbs_util::CreateRecvWr(/*wr_id=*/0, &rsge, /*num_sge=*/1);
verbs_util::PostRecv(remote.qp, recv);

ibv_sge lsge = verbs_util::CreateSge(local.buffer.span(), local.mr);
lsge.length = kPayloadLength;
ibv_send_wr send =
verbs_util::CreateSendWr(/*wr_id=*/1, &lsge, /*num_sge=*/1);
send.wr.ud.ah = local.other_ah;
send.wr.ud.remote_qpn = remote.qp->qp_num;
send.wr.ud.remote_qkey = kQKey;
verbs_util::PostSend(local.qp, send);

ibv_wc completion = verbs_util::WaitForCompletion(local.cq).value();
EXPECT_EQ(IBV_WC_SUCCESS, completion.status);
EXPECT_EQ(local.qp->qp_num, completion.qp_num);
EXPECT_EQ(1, completion.wr_id);
}

// Read not supported on UD.
TEST_F(LoopbackUdQpTest, Read) {
auto client_pair_or = CreateConnectedClientsPair();
Expand Down
8 changes: 6 additions & 2 deletions cases/mw_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,9 @@ TEST_P(MWBindTest, MissingBind) {
const int kMrAccess = IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_ATOMIC |
IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE;
const int kBindAccess = IBV_ACCESS_MW_BIND;
const ibv_wc_status kExpected = IBV_WC_MW_BIND_ERR;
const ibv_wc_status kExpected =
Introspection().CorrectlyReportsMemoryWindowErrors() ? IBV_WC_MW_BIND_ERR
: IBV_WC_SUCCESS;
AttemptBind(setup, kMrAccess, kBindAccess, kExpected);
}

Expand Down Expand Up @@ -934,7 +936,9 @@ TEST_P(MWBindTest, NoMrBindAccess) {
ASSERT_OK_AND_ASSIGN(BasicSetup setup, CreateBasicSetup());
const int kMrAccess = IBV_ACCESS_REMOTE_READ;
const int kBindAccess = IBV_ACCESS_REMOTE_READ;
const ibv_wc_status kExpected = IBV_WC_MW_BIND_ERR;
const ibv_wc_status kExpected =
Introspection().CorrectlyReportsMemoryWindowErrors() ? IBV_WC_MW_BIND_ERR
: IBV_WC_SUCCESS;
AttemptBind(setup, kMrAccess, kBindAccess, kExpected);
}

Expand Down
3 changes: 2 additions & 1 deletion cases/srq_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ TEST_F(SrqTest, ExceedsMaxWrInfinitChain) {
ibv_recv_wr* bad_wr = nullptr;
int result = ibv_post_srq_recv(setup.srq, &recv, &bad_wr);
EXPECT_EQ(bad_wr, &recv);
EXPECT_EQ(result, -1); // mlx4 uses -1
// mlx4 uses -1, mlx5 uses ENOMEM
EXPECT_THAT(result, testing::AnyOf(-1, ENOMEM));
}

TEST_F(SrqTest, ExceedsMaxSge) {
Expand Down
2 changes: 1 addition & 1 deletion cases/status_matchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

#define ASSIGN_OR_RETURN_IMPL(statusor, lhs, rexpr) \
auto statusor = (rexpr); \
if (PREDICT_FALSE(!statusor.ok())) { \
if (!statusor.ok()) { \
return statusor.status(); \
} \
lhs = std::move(statusor.value())
Expand Down
10 changes: 10 additions & 0 deletions impl/introspection_mlx5.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ class IntrospectionMlx5 : public NicIntrospection {

bool SupportsRcSendWithInvalidate() const { return false; }

bool SupportsRcRemoteMwAtomic() const { return false; }

// CQAdvancedTest::RecvSharedCq failure with multiple outstanding recv
// requests. Completions are returned but no data transferred which results
// in the WaitingForChange to fail.
// TODO(author1): determine if there is a test issue.
bool SupportsMultipleOutstandingRecvRequests() const { return false; }

bool CorrectlyReportsInvalidObjects() const { return false; }

bool CorrectlyReportsCompChannelErrors() const { return false; }
Expand All @@ -41,6 +49,8 @@ class IntrospectionMlx5 : public NicIntrospection {

bool CorrectlyReportsInvalidSizeErrors() const { return false; }

bool CorrectlyReportsInvalidRecvLengthErrors() const { return false; }

private:
IntrospectionMlx5() = delete;
~IntrospectionMlx5() = default;
Expand Down
9 changes: 9 additions & 0 deletions public/introspection.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ class NicIntrospection {
// Returns true if the NIC supports RC SendWithInvalidate.
virtual bool SupportsRcSendWithInvalidate() const { return true; }

// Returns true if the NIC supports RC Remote Memory Window Atomic.
virtual bool SupportsRcRemoteMwAtomic() const { return true; }

// Returns true if the NIC supports multiple outstanding recv requests.
virtual bool SupportsMultipleOutstandingRecvRequests() const { return true; }

// Returns true if the NIC allows destroying PDs with outstanding AHs.
virtual bool CanDestroyPdWithAhOutstanding() const { return false; }

Expand Down Expand Up @@ -98,6 +104,9 @@ class NicIntrospection {
// Reports true if NIC robustly handles invalid size on atomic operations.
virtual bool CorrectlyReportsInvalidSizeErrors() const { return true; }

// Reports true if NIC robustly handles invalid receive length.
virtual bool CorrectlyReportsInvalidRecvLengthErrors() const { return true; }

// Returns true if the provider requires the use of file backed shared
// memory.
virtual bool RequiresSharedMemory() const { return false; }
Expand Down

0 comments on commit 3a27bfd

Please sign in to comment.