This is an automated email from the ASF dual-hosted git repository.

chenBright pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git


The following commit(s) were added to refs/heads/master by this push:
     new e4900b5a detect and negotiate mtu in rdma (#3304)
e4900b5a is described below

commit e4900b5ad81ec308ddafde7da16f9225b518ed56
Author: randomkang <[email protected]>
AuthorDate: Thu Nov 5 17:44:02 2026 +0800

    detect and negotiate mtu in rdma (#3304)
---
 src/brpc/rdma/rdma_endpoint.cpp    |  25 +++-
 src/brpc/rdma/rdma_endpoint.h      |   7 +
 src/brpc/rdma/rdma_handshake.cpp   |  26 ++++
 src/brpc/rdma/rdma_handshake.h     |   8 ++
 src/brpc/rdma/rdma_handshake.proto |  10 ++
 src/brpc/rdma/rdma_helper.cpp      |   8 ++
 src/brpc/rdma/rdma_helper.h        |   3 +
 test/brpc_rdma_unittest.cpp        | 253 +++++++++++++++++++++++++++++++++++++
 8 files changed, 339 insertions(+), 1 deletion(-)

diff --git a/src/brpc/rdma/rdma_endpoint.cpp b/src/brpc/rdma/rdma_endpoint.cpp
index 0dc41c9d..110279b7 100644
--- a/src/brpc/rdma/rdma_endpoint.cpp
+++ b/src/brpc/rdma/rdma_endpoint.cpp
@@ -17,6 +17,7 @@
 
 #if BRPC_WITH_RDMA
 
+#include <algorithm>                            // std::min
 #include <gflags/gflags.h>
 #include "butil/fd_utility.h"
 #include "butil/logging.h"                   // CHECK, LOG
@@ -1401,6 +1402,15 @@ int RdmaEndpoint::StartCqEvents() {
 }
 
 int RdmaEndpoint::BringUpQp(const ParsedHello& remote, bool is_server) {
+    // MTU negotiation (server side): compute min(local, client) and store it
+    // so FillLocalRdmaHello can advertise the negotiated value in the server
+    // hello reply. This is done before the g_skip_rdma_init early-return so
+    // that UT (which skips real QP bring-up) still sets _outgoing_mtu.
+    if (is_server && remote.path_mtu.has_value()) {
+        uint32_t local_mtu = GetRdmaActiveMtu();
+        _outgoing_mtu = std::min(local_mtu, *remote.path_mtu);
+    }
+
     if (BAIDU_UNLIKELY(g_skip_rdma_init)) {
         // For UT
         return 0;
@@ -1448,7 +1458,20 @@ int RdmaEndpoint::BringUpQp(const ParsedHello& remote, 
bool is_server) {
     }
 
     attr.qp_state = IBV_QPS_RTR;
-    attr.path_mtu = IBV_MTU_1024;  // TODO: support more mtu in future
+    // MTU negotiation: use the peer-advertised MTU if available, otherwise
+    // fall back to the legacy default (IBV_MTU_1024).
+    //   Server side: _outgoing_mtu was already computed at function entry;
+    //     reuse it for the QP path_mtu attribute.
+    //   Client side: remote.path_mtu is already the server's negotiated
+    //     min(local, client) and we use it as-is.
+    uint32_t negotiated_mtu =
+        std::min(static_cast<uint32_t>(IBV_MTU_1024), GetRdmaActiveMtu());
+    if (is_server && _outgoing_mtu.has_value()) {
+        negotiated_mtu = *_outgoing_mtu;
+    } else if (!is_server && remote.path_mtu.has_value()) {
+        negotiated_mtu = *remote.path_mtu;
+    }
+    attr.path_mtu = static_cast<ibv_mtu>(negotiated_mtu);
     attr.ah_attr.grh.dgid = remote.gid;
     attr.ah_attr.grh.flow_label = 0;
     attr.ah_attr.grh.sgid_index = GetRdmaGidIndex();
diff --git a/src/brpc/rdma/rdma_endpoint.h b/src/brpc/rdma/rdma_endpoint.h
index eda5e558..16dd782d 100644
--- a/src/brpc/rdma/rdma_endpoint.h
+++ b/src/brpc/rdma/rdma_endpoint.h
@@ -314,6 +314,13 @@ private:
     //           QP reached RTS (filled in BringUpQp).
     butil::optional<ibv_ece> _outgoing_ece;
 
+    // MTU payload to advertise in the next local hello:
+    //   Client: the locally queried active MTU (filled
+    //           before C_HELLO_SEND);
+    //   Server: the negotiated MTU = min(local_active_mtu, client_mtu)
+    //           (filled in BringUpQp).
+    butil::optional<uint32_t> _outgoing_mtu;
+
     // rdma resource
     RdmaResource* _resource;
 
diff --git a/src/brpc/rdma/rdma_handshake.cpp b/src/brpc/rdma/rdma_handshake.cpp
index 17c67155..63681999 100644
--- a/src/brpc/rdma/rdma_handshake.cpp
+++ b/src/brpc/rdma/rdma_handshake.cpp
@@ -286,6 +286,12 @@ bool ValidRdmaHello(const RdmaHello& msg) {
     if (msg.qp_num() == 0 && !g_skip_rdma_init) {
         return false;
     }
+    // Validate MTU: must be a valid ibv_mtu enum value 
(IBV_MTU_256..IBV_MTU_4096)
+    // to prevent invalid values from being passed to ibv_modify_qp.
+    if (msg.has_mtu() &&
+        (msg.mtu() < IBV_MTU_256 || msg.mtu() > IBV_MTU_4096)) {
+        return false;
+    }
     return true;
 }
 
@@ -318,6 +324,15 @@ void FillLocalRdmaHello(const RdmaEndpoint* ep, RdmaHello* 
msg) {
         ece->set_options(ep->_outgoing_ece->options);
         ece->set_comp_mask(ep->_outgoing_ece->comp_mask);
     }
+
+    // Advertise MTU if the endpoint has a value to advertise.
+    // Client side: queried local active MTU (filled before C_HELLO_SEND).
+    // Server side: negotiated MTU = min(local_mtu, client_mtu)
+    //   (filled in BringUpQp).
+    // nullopt -> omit the field (peer falls back to IBV_MTU_1024).
+    if (ep->_outgoing_mtu.has_value()) {
+        msg->set_mtu(*ep->_outgoing_mtu);
+    }
 }
 
 int ReadAndParseV3Hello(RdmaEndpoint* ep, RdmaHello* out) {
@@ -380,6 +395,9 @@ void TranslateHello(const RdmaHello& msg, ParsedHello* out) 
{
         ece.comp_mask = msg.ece().comp_mask();
         out->ece = ece;
     }
+    if (msg.has_mtu()) {
+        out->path_mtu = msg.mtu();
+    }
 }
 
 }  // namespace v3_wire
@@ -400,6 +418,14 @@ int RdmaHandshakeClientV3::SendLocalHello() {
         }
     }
 
+    // Query local active MTU so it can be advertised in the client hello.
+    // Best-effort: any failure just means we won't advertise MTU
+    // (the peer falls back to IBV_MTU_1024).
+    // In UT mode (g_skip_rdma_init=true), GetRdmaActiveMtu() returns the
+    // default IBV_MTU_1024 (g_active_mtu is never overwritten by OpenDevice),
+    // so the client hello still includes a valid MTU.
+    _ep->_outgoing_mtu = GetRdmaActiveMtu();
+
     RdmaHello local_msg{};
     v3_wire::FillLocalRdmaHello(_ep, &local_msg);
     return v3_wire::WriteV3Hello(_ep, local_msg);
diff --git a/src/brpc/rdma/rdma_handshake.h b/src/brpc/rdma/rdma_handshake.h
index 2d10220a..b0d4cfa4 100644
--- a/src/brpc/rdma/rdma_handshake.h
+++ b/src/brpc/rdma/rdma_handshake.h
@@ -53,6 +53,14 @@ struct ParsedHello {
     //   - on the server side: the client's queried ECE capabilities;
     //   - on the client side: the server's reduced/negotiated ECE.
     butil::optional<ibv_ece> ece;
+
+    // MTU negotiation, v3 handshake only.
+    // nullopt means the peer did not advertise an MTU (v2 peer or older v3
+    // peer that predates MTU negotiation). When engaged:
+    //   - on the server side: the client's active MTU;
+    //   - on the client side: the server's negotiated MTU
+    //     (= min(local_active_mtu, client_mtu)).
+    butil::optional<uint32_t> path_mtu;
 };
 
 // Result of reading/parsing a peer's hello (see ReceiveAndParseRemoteHello).
diff --git a/src/brpc/rdma/rdma_handshake.proto 
b/src/brpc/rdma/rdma_handshake.proto
index b5627b2e..08491657 100644
--- a/src/brpc/rdma/rdma_handshake.proto
+++ b/src/brpc/rdma/rdma_handshake.proto
@@ -55,6 +55,16 @@ message RdmaHello {
     //   Server hello: carries the REDUCED/negotiated ECE
     //                   queried after the QP reached RTS.
     optional RdmaEce ece = 7;
+
+    // MTU negotiation (v3 only).
+    // Optional: carries the sender's active MTU (IBV_MTU_256 .. IBV_MTU_4096).
+    // Absent on v2 peers and on older v3 peers that predate MTU negotiation;
+    // the receiver then falls back to IBV_MTU_1024.
+    //
+    // Semantics differ by sender role:
+    //   Client hello: the locally queried active MTU of the RDMA port.
+    //   Server hello: the negotiated MTU = min(local_active_mtu, client_mtu).
+    optional uint32 mtu = 8;
 }
 
 // Mirrors struct ibv_ece { uint32 vendor_id; uint32 options; uint32 
comp_mask; }.
diff --git a/src/brpc/rdma/rdma_helper.cpp b/src/brpc/rdma/rdma_helper.cpp
index 7e671a85..80bd96e8 100644
--- a/src/brpc/rdma/rdma_helper.cpp
+++ b/src/brpc/rdma/rdma_helper.cpp
@@ -83,6 +83,7 @@ static int g_gid_tbl_len = 0;
 static uint8_t g_gid_index = 0;
 static ibv_gid g_gid;
 static uint16_t g_lid;
+static uint32_t g_active_mtu = IBV_MTU_1024;
 static int g_max_sge = 0;
 static uint32_t g_vendor_id = 0;
 static uint8_t g_port_num = 1;
@@ -459,6 +460,7 @@ static ibv_context* OpenDevice(int num_total, int* 
num_available_devices) {
                 ret_context = context.release();
                 g_gid_tbl_len = attr.gid_tbl_len;
                 g_lid = attr.lid;
+                g_active_mtu = attr.active_mtu;
             } else {
                 LOG(INFO) << "Device name not match: " << context->device->name
                           << " vs " << FLAGS_rdma_device;
@@ -468,6 +470,7 @@ static ibv_context* OpenDevice(int num_total, int* 
num_available_devices) {
             ret_context = context.release();
             g_gid_tbl_len = attr.gid_tbl_len;
             g_lid = attr.lid;
+            g_active_mtu = attr.active_mtu;
         }
     }
     return ret_context;
@@ -517,6 +520,7 @@ static void GlobalRdmaInitializeOrDieImpl() {
         LOG(INFO) << "RDMA device: " << g_context->device->name;
     }
     LOG(INFO) << "RDMA LID: " << g_lid;
+    LOG(INFO) << "RDMA Active MTU: " << g_active_mtu;
     if (!FindRdmaGid(g_context)) {
         LOG(ERROR) << "Fail to find available RDMA GID";
         ExitWithError();
@@ -687,6 +691,10 @@ uint16_t GetRdmaLid() {
     return g_lid;
 }
 
+uint32_t GetRdmaActiveMtu() {
+    return g_active_mtu;
+}
+
 uint8_t GetRdmaGidIndex() {
     return g_gid_index;
 }
diff --git a/src/brpc/rdma/rdma_helper.h b/src/brpc/rdma/rdma_helper.h
index 2383d2d8..61a63229 100644
--- a/src/brpc/rdma/rdma_helper.h
+++ b/src/brpc/rdma/rdma_helper.h
@@ -68,6 +68,9 @@ ibv_gid GetRdmaGid();
 // Return Global LID
 uint16_t GetRdmaLid();
 
+// Return active MTU of the RDMA port (IBV_MTU_256 .. IBV_MTU_4096).
+uint32_t GetRdmaActiveMtu();
+
 // Return suggested comp vector for CQ
 int GetRdmaCompVector();
 
diff --git a/test/brpc_rdma_unittest.cpp b/test/brpc_rdma_unittest.cpp
index 6ec54ed9..59bd9da5 100644
--- a/test/brpc_rdma_unittest.cpp
+++ b/test/brpc_rdma_unittest.cpp
@@ -43,6 +43,8 @@
 #include "brpc/rdma_transport.h"
 #include "brpc/rdma/block_pool.h"
 #include "brpc/rdma/rdma_endpoint.h"
+#include <algorithm>                            // std::min
+
 #include "brpc/rdma/rdma_handshake.h"
 #include "brpc/rdma/rdma_handshake_constants.h"
 #include "brpc/rdma/rdma_handshake.pb.h"
@@ -2202,6 +2204,257 @@ TEST_F(RdmaTest, 
server_alloc_resource_fail_fallback_tcp) {
     StopServer();
 }
 
+// Build a valid v3 hello that also carries an MTU value.
+rdma::RdmaHello MakeValidV3HelloWithMtu(uint32_t mtu) {
+    rdma::RdmaHello msg = MakeValidV3Hello();
+    msg.set_mtu(mtu);
+    return msg;
+}
+
+// A client hello carrying MTU must not break the server handshake:
+// the server still parses the hello and advances to S_ACK_WAIT.
+TEST_F(RdmaTest, v3_server_accepts_client_hello_with_mtu) {
+    StartServer();
+
+    sockaddr_in addr;
+    bzero((char*)&addr, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(PORT);
+    butil::fd_guard sockfd(socket(AF_INET, SOCK_STREAM, 0));
+    ASSERT_TRUE(sockfd >= 0);
+    ASSERT_EQ(0, connect(sockfd, (sockaddr*)&addr, sizeof(sockaddr)));
+    Socket* s = WaitForServerSocket();
+    ASSERT_TRUE(s != NULL);
+
+    rdma::RdmaHello msg = MakeValidV3HelloWithMtu(IBV_MTU_4096);
+    std::string packet = MakeV3Packet(msg);
+    ASSERT_EQ((ssize_t)packet.size(),
+              write(sockfd, packet.data(), packet.size()));
+
+    ASSERT_RDMA_STATE(rdma::RdmaEndpoint::S_ACK_WAIT, RdmaTransportOf(s));
+
+    rdma::RdmaHello reply;
+    ReadServerV3Reply(sockfd, &reply);
+
+    // ACK flags=0 -> clean FALLBACK_TCP so the test ends without hardware.
+    uint32_t flags = butil::HostToNet32(0);
+    ASSERT_EQ((ssize_t)sizeof(flags), write(sockfd, &flags, sizeof(flags)));
+    ASSERT_RDMA_STATE(rdma::RdmaEndpoint::FALLBACK_TCP, RdmaTransportOf(s));
+
+    sockfd.reset(-1);
+    ASSERT_TRUE(WaitForServerSocketGone());
+    StopServer();
+}
+
+// The server reply must carry a negotiated MTU when the client advertised one.
+// The server computes min(local, client) at the start of BringUpQp (before the
+// g_skip_rdma_init early-return), so _outgoing_mtu is set even in UT mode;
+// FillLocalRdmaHello then includes it in the reply.
+TEST_F(RdmaTest, v3_server_reply_has_negotiated_mtu) {
+    StartServer();
+
+    sockaddr_in addr;
+    bzero((char*)&addr, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(PORT);
+    butil::fd_guard sockfd(socket(AF_INET, SOCK_STREAM, 0));
+    ASSERT_TRUE(sockfd >= 0);
+    ASSERT_EQ(0, connect(sockfd, (sockaddr*)&addr, sizeof(sockaddr)));
+    Socket* s = WaitForServerSocket();
+    ASSERT_TRUE(s != NULL);
+
+    // Advertise a non-default MTU so we can verify negotiation.
+    rdma::RdmaHello msg = MakeValidV3HelloWithMtu(IBV_MTU_4096);
+    std::string packet = MakeV3Packet(msg);
+    ASSERT_EQ((ssize_t)packet.size(),
+              write(sockfd, packet.data(), packet.size()));
+
+    rdma::RdmaHello reply;
+    ReadServerV3Reply(sockfd, &reply);
+
+    // The server should advertise a negotiated MTU in its reply.
+    EXPECT_TRUE(reply.has_mtu());
+    // Negotiated MTU = min(local_active_mtu, client_mtu). In UT mode
+    // (g_skip_rdma_init=true) GetRdmaActiveMtu() returns the default
+    // IBV_MTU_1024, so negotiated = min(1024, 4096) = 1024. With real
+    // hardware (FLAGS_rdma_test_enable=true) the local active MTU may be
+    // larger (e.g. 4096), so compare against min(local, advertised)
+    // instead of a hard-coded value.
+    uint32_t expected_mtu = std::min(rdma::GetRdmaActiveMtu(),
+                                     static_cast<uint32_t>(IBV_MTU_4096));
+    EXPECT_EQ(expected_mtu, reply.mtu());
+
+    uint32_t flags = butil::HostToNet32(0);
+    ASSERT_EQ((ssize_t)sizeof(flags), write(sockfd, &flags, sizeof(flags)));
+
+    sockfd.reset(-1);
+    ASSERT_TRUE(WaitForServerSocketGone());
+    StopServer();
+}
+
+// When the client does NOT advertise an MTU (e.g., v2 peer or older v3 peer),
+// the server must NOT include an MTU in its reply (backward-compatible
+// degradation to legacy IBV_MTU_1024 default).
+TEST_F(RdmaTest, v3_server_reply_has_no_mtu_without_client_mtu) {
+    StartServer();
+
+    sockaddr_in addr;
+    bzero((char*)&addr, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(PORT);
+    butil::fd_guard sockfd(socket(AF_INET, SOCK_STREAM, 0));
+    ASSERT_TRUE(sockfd >= 0);
+    ASSERT_EQ(0, connect(sockfd, (sockaddr*)&addr, sizeof(sockaddr)));
+    Socket* s = WaitForServerSocket();
+    ASSERT_TRUE(s != NULL);
+
+    // Client hello without MTU field.
+    rdma::RdmaHello msg = MakeValidV3Hello();
+    std::string packet = MakeV3Packet(msg);
+    ASSERT_EQ((ssize_t)packet.size(),
+              write(sockfd, packet.data(), packet.size()));
+
+    rdma::RdmaHello reply;
+    ReadServerV3Reply(sockfd, &reply);
+
+    // Server must not advertise MTU when client didn't.
+    EXPECT_FALSE(reply.has_mtu());
+
+    uint32_t flags = butil::HostToNet32(0);
+    ASSERT_EQ((ssize_t)sizeof(flags), write(sockfd, &flags, sizeof(flags)));
+
+    sockfd.reset(-1);
+    ASSERT_TRUE(WaitForServerSocketGone());
+    StopServer();
+}
+
+// A client hello with an out-of-range MTU (e.g., 0 or > IBV_MTU_4096) must be
+// rejected by ValidRdmaHello. Per the handshake-fallback design, the server
+// does NOT close the connection; instead it degrades to TCP fallback: the
+// endpoint enters S_ACK_WAIT with RDMA_OFF, the reply carries no MTU, and a
+// subsequent ACK-without-RDMA finalizes FALLBACK_TCP.
+TEST_F(RdmaTest, v3_server_rejects_invalid_mtu) {
+    StartServer();
+
+    sockaddr_in addr;
+    bzero((char*)&addr, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(PORT);
+
+    // Test with MTU = 0 (below IBV_MTU_256).
+    butil::fd_guard sockfd1(socket(AF_INET, SOCK_STREAM, 0));
+    ASSERT_TRUE(sockfd1 >= 0);
+    ASSERT_EQ(0, connect(sockfd1, (sockaddr*)&addr, sizeof(sockaddr)));
+    Socket* s = WaitForServerSocket();
+    ASSERT_TRUE(s != NULL);
+
+    rdma::RdmaHello msg = MakeValidV3HelloWithMtu(0);
+    std::string packet = MakeV3Packet(msg);
+    ASSERT_EQ((ssize_t)packet.size(),
+              write(sockfd1, packet.data(), packet.size()));
+
+    // The server rejects the hello but falls back to TCP instead of failing.
+    s = GetSocketFromServer(0);
+    ASSERT_TRUE(s != NULL);
+    ASSERT_RDMA_STATE(rdma::RdmaEndpoint::S_ACK_WAIT, RdmaTransportOf(s));
+    ASSERT_EQ(RdmaTransport::RDMA_OFF, RdmaTransportOf(s)->_rdma_state);
+    ASSERT_FALSE(s->Failed());
+
+    // The fallback reply must not carry an MTU.
+    rdma::RdmaHello reply;
+    ReadServerV3Reply(sockfd1, &reply);
+    EXPECT_FALSE(reply.has_mtu());
+
+    // Ack without RDMA so the server finalizes FALLBACK_TCP.
+    uint32_t flags = butil::HostToNet32(0);
+    ASSERT_EQ(sizeof(flags), write(sockfd1, &flags, sizeof(flags)));
+    ASSERT_RDMA_STATE(rdma::RdmaEndpoint::FALLBACK_TCP, RdmaTransportOf(s));
+    ASSERT_FALSE(s->Failed());
+
+    sockfd1.reset(-1);
+    ASSERT_TRUE(WaitForServerSocketGone());
+
+    // Test with MTU = 6 (above IBV_MTU_4096).
+    butil::fd_guard sockfd2(socket(AF_INET, SOCK_STREAM, 0));
+    ASSERT_TRUE(sockfd2 >= 0);
+    ASSERT_EQ(0, connect(sockfd2, (sockaddr*)&addr, sizeof(sockaddr)));
+    s = WaitForServerSocket();
+    ASSERT_TRUE(s != NULL);
+
+    msg = MakeValidV3HelloWithMtu(6);
+    packet = MakeV3Packet(msg);
+    ASSERT_EQ((ssize_t)packet.size(),
+              write(sockfd2, packet.data(), packet.size()));
+
+    s = GetSocketFromServer(0);
+    ASSERT_TRUE(s != NULL);
+    ASSERT_RDMA_STATE(rdma::RdmaEndpoint::S_ACK_WAIT, RdmaTransportOf(s));
+    ASSERT_EQ(RdmaTransport::RDMA_OFF, RdmaTransportOf(s)->_rdma_state);
+    ASSERT_FALSE(s->Failed());
+
+    ReadServerV3Reply(sockfd2, &reply);
+    EXPECT_FALSE(reply.has_mtu());
+
+    flags = butil::HostToNet32(0);
+    ASSERT_EQ(sizeof(flags), write(sockfd2, &flags, sizeof(flags)));
+    ASSERT_RDMA_STATE(rdma::RdmaEndpoint::FALLBACK_TCP, RdmaTransportOf(s));
+    ASSERT_FALSE(s->Failed());
+
+    sockfd2.reset(-1);
+    ASSERT_TRUE(WaitForServerSocketGone());
+
+    StopServer();
+}
+
+// Verify the client includes its local MTU in the v3 hello.
+TEST_F(RdmaTest, v3_client_hello_includes_mtu) {
+    HandshakeVersionFlag _hsv(3);
+
+    butil::fd_guard sockfd(butil::tcp_listen(g_ep));
+    EXPECT_TRUE(sockfd >= 0);
+
+    Channel channel;
+    ChannelOptions chan_options;
+    chan_options.socket_mode = SOCKET_MODE_RDMA;
+    chan_options.connect_timeout_ms = 500;
+    chan_options.timeout_ms = 500;
+    chan_options.max_retry = 0;
+    ASSERT_EQ(0, channel.Init(g_ep, &chan_options));
+
+    Controller cntl;
+    test::EchoRequest req;
+    test::EchoResponse res;
+    req.set_message(__FUNCTION__);
+    google::protobuf::Closure* done = DoNothing();
+    ::test::EchoService::Stub(&channel).Echo(&cntl, &req, &res, done);
+
+    butil::fd_guard acc_fd(accept(sockfd, NULL, NULL));
+    ASSERT_TRUE(acc_fd >= 0);
+
+    // Read 4B magic + 4B pb_size + body from the client hello.
+    uint8_t hdr[8];
+    ASSERT_EQ(8, read(acc_fd, hdr, 8));
+    ASSERT_EQ(0, memcmp(hdr, "RDM3", 4));
+    uint32_t pb_size = butil::NetToHost32(*reinterpret_cast<uint32_t*>(hdr + 
4));
+    ASSERT_GT(pb_size, 0u);
+    ASSERT_LE(pb_size, 4096u);
+    std::string body(pb_size, '\0');
+    ASSERT_EQ((ssize_t)pb_size, read(acc_fd, &body[0], pb_size));
+
+    rdma::RdmaHello hello;
+    ASSERT_TRUE(hello.ParseFromString(body));
+
+    // The client hello must carry the locally queried active MTU.
+    // In UT mode (g_skip_rdma_init=true), OpenDevice is never called so
+    // GetRdmaActiveMtu() returns the default IBV_MTU_1024; with real
+    // hardware (FLAGS_rdma_test_enable=true) it returns the port's actual
+    // active MTU, so compare against it instead of a hard-coded value.
+    EXPECT_TRUE(hello.has_mtu());
+    EXPECT_EQ(rdma::GetRdmaActiveMtu(), hello.mtu());
+
+    bthread_id_join(cntl.call_id());
+}
+
 TEST_F(RdmaTest, try_global_disable_rdma) {
     StartServer();
     rdma::g_rdma_available.store(false, butil::memory_order_relaxed);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to