]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/msgr/test_frames_v2.cc
import 15.2.5
[ceph.git] / ceph / src / test / msgr / test_frames_v2.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2020 Red Hat
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include "msg/async/frames_v2.h"
16
17 #include <numeric>
18 #include <ostream>
19 #include <string>
20 #include <tuple>
21
22 #include "auth/Auth.h"
23 #include "common/ceph_argparse.h"
24 #include "global/global_init.h"
25 #include "global/global_context.h"
26 #include "include/Context.h"
27
28 #include <gtest/gtest.h>
29
30 namespace ceph::msgr::v2 {
31
32 // MessageFrame with the first segment not fixed to ceph_msg_header2
33 struct TestFrame : Frame<TestFrame,
34 /* four segments */
35 segment_t::DEFAULT_ALIGNMENT,
36 segment_t::DEFAULT_ALIGNMENT,
37 segment_t::DEFAULT_ALIGNMENT,
38 segment_t::PAGE_SIZE_ALIGNMENT> {
39 static constexpr Tag tag = static_cast<Tag>(123);
40
41 static TestFrame Encode(const bufferlist& header,
42 const bufferlist& front,
43 const bufferlist& middle,
44 const bufferlist& data) {
45 TestFrame f;
46 f.segments[SegmentIndex::Msg::HEADER] = header;
47 f.segments[SegmentIndex::Msg::FRONT] = front;
48 f.segments[SegmentIndex::Msg::MIDDLE] = middle;
49 f.segments[SegmentIndex::Msg::DATA] = data;
50
51 // discard cached crcs for perf tests
52 f.segments[SegmentIndex::Msg::HEADER].invalidate_crc();
53 f.segments[SegmentIndex::Msg::FRONT].invalidate_crc();
54 f.segments[SegmentIndex::Msg::MIDDLE].invalidate_crc();
55 f.segments[SegmentIndex::Msg::DATA].invalidate_crc();
56 return f;
57 }
58
59 static TestFrame Decode(segment_bls_t& segment_bls) {
60 TestFrame f;
61 // Transfer segments' bufferlists. If segment_bls contains
62 // less than SegmentsNumV segments, the missing ones will be
63 // seen as empty.
64 for (size_t i = 0; i < segment_bls.size(); i++) {
65 f.segments[i] = std::move(segment_bls[i]);
66 }
67 return f;
68 }
69
70 bufferlist& header() {
71 return segments[SegmentIndex::Msg::HEADER];
72 }
73 bufferlist& front() {
74 return segments[SegmentIndex::Msg::FRONT];
75 }
76 bufferlist& middle() {
77 return segments[SegmentIndex::Msg::MIDDLE];
78 }
79 bufferlist& data() {
80 return segments[SegmentIndex::Msg::DATA];
81 }
82
83 protected:
84 using Frame::Frame;
85 };
86
87 struct mode_t {
88 bool is_rev1;
89 bool is_secure;
90 };
91
92 static std::ostream& operator<<(std::ostream& os, const mode_t& m) {
93 os << "msgr2." << (m.is_rev1 ? "1" : "0")
94 << (m.is_secure ? "-secure" : "-crc");
95 return os;
96 }
97
98 static const mode_t modes[] = {
99 {false, false},
100 {false, true},
101 {true, false},
102 {true, true},
103 };
104
105 struct round_trip_instance_t {
106 uint32_t header_len;
107 uint32_t front_len;
108 uint32_t middle_len;
109 uint32_t data_len;
110
111 // expected number of segments (same for each mode)
112 size_t num_segments;
113 // expected layout (different for each mode)
114 uint32_t onwire_lens[4][MAX_NUM_SEGMENTS + 2];
115 };
116
117 static std::ostream& operator<<(std::ostream& os,
118 const round_trip_instance_t& rti) {
119 os << rti.header_len << "+" << rti.front_len << "+"
120 << rti.middle_len << "+" << rti.data_len;
121 return os;
122 }
123
124 static bufferlist make_bufferlist(size_t len, char c) {
125 bufferlist bl;
126 if (len > 0) {
127 bl.reserve(len);
128 bl.append(std::string(len, c));
129 }
130 return bl;
131 }
132
133 bool disassemble_frame(FrameAssembler& frame_asm, bufferlist& frame_bl,
134 Tag& tag, segment_bls_t& segment_bls) {
135 bufferlist preamble_bl;
136 frame_bl.splice(0, frame_asm.get_preamble_onwire_len(), &preamble_bl);
137 tag = frame_asm.disassemble_preamble(preamble_bl);
138
139 do {
140 size_t seg_idx = segment_bls.size();
141 segment_bls.emplace_back();
142
143 uint32_t onwire_len = frame_asm.get_segment_onwire_len(seg_idx);
144 if (onwire_len > 0) {
145 frame_bl.splice(0, onwire_len, &segment_bls.back());
146 }
147 } while (segment_bls.size() < frame_asm.get_num_segments());
148
149 bufferlist epilogue_bl;
150 uint32_t epilogue_onwire_len = frame_asm.get_epilogue_onwire_len();
151 if (epilogue_onwire_len > 0) {
152 frame_bl.splice(0, epilogue_onwire_len, &epilogue_bl);
153 }
154 frame_asm.disassemble_first_segment(preamble_bl, segment_bls[0]);
155 return frame_asm.disassemble_remaining_segments(segment_bls.data(),
156 epilogue_bl);
157 }
158
159 class RoundTripTestBase : public ::testing::TestWithParam<
160 std::tuple<round_trip_instance_t, mode_t>> {
161 protected:
162 RoundTripTestBase()
163 : m_tx_frame_asm(&m_tx_crypto, std::get<1>(GetParam()).is_rev1),
164 m_rx_frame_asm(&m_rx_crypto, std::get<1>(GetParam()).is_rev1),
165 m_header(make_bufferlist(std::get<0>(GetParam()).header_len, 'H')),
166 m_front(make_bufferlist(std::get<0>(GetParam()).front_len, 'F')),
167 m_middle(make_bufferlist(std::get<0>(GetParam()).middle_len, 'M')),
168 m_data(make_bufferlist(std::get<0>(GetParam()).data_len, 'D')) {
169 const auto& m = std::get<1>(GetParam());
170 if (m.is_secure) {
171 AuthConnectionMeta auth_meta;
172 auth_meta.con_mode = CEPH_CON_MODE_SECURE;
173 // see AuthConnectionMeta::get_connection_secret_length()
174 auth_meta.connection_secret.resize(64);
175 g_ceph_context->random()->get_bytes(auth_meta.connection_secret.data(),
176 auth_meta.connection_secret.size());
177 m_tx_crypto = ceph::crypto::onwire::rxtx_t::create_handler_pair(
178 g_ceph_context, auth_meta, /*new_nonce_format=*/m.is_rev1,
179 /*crossed=*/false);
180 m_rx_crypto = ceph::crypto::onwire::rxtx_t::create_handler_pair(
181 g_ceph_context, auth_meta, /*new_nonce_format=*/m.is_rev1,
182 /*crossed=*/true);
183 }
184 }
185
186 void check_frame_assembler(const FrameAssembler& frame_asm) {
187 const auto& [rti, m] = GetParam();
188 const auto& onwire_lens = rti.onwire_lens[m.is_rev1 << 1 | m.is_secure];
189 EXPECT_EQ(rti.header_len + rti.front_len + rti.middle_len + rti.data_len,
190 frame_asm.get_frame_logical_len());
191 ASSERT_EQ(rti.num_segments, frame_asm.get_num_segments());
192 EXPECT_EQ(onwire_lens[0], frame_asm.get_preamble_onwire_len());
193 for (size_t i = 0; i < rti.num_segments; i++) {
194 EXPECT_EQ(onwire_lens[i + 1], frame_asm.get_segment_onwire_len(i));
195 }
196 EXPECT_EQ(onwire_lens[rti.num_segments + 1],
197 frame_asm.get_epilogue_onwire_len());
198 EXPECT_EQ(std::accumulate(std::begin(onwire_lens), std::end(onwire_lens),
199 uint64_t(0)),
200 frame_asm.get_frame_onwire_len());
201 }
202
203 void test_round_trip() {
204 auto tx_frame = TestFrame::Encode(m_header, m_front, m_middle, m_data);
205 auto onwire_bl = tx_frame.get_buffer(m_tx_frame_asm);
206 check_frame_assembler(m_tx_frame_asm);
207 EXPECT_EQ(m_tx_frame_asm.get_frame_onwire_len(), onwire_bl.length());
208
209 Tag rx_tag;
210 segment_bls_t rx_segment_bls;
211 EXPECT_TRUE(disassemble_frame(m_rx_frame_asm, onwire_bl, rx_tag,
212 rx_segment_bls));
213 check_frame_assembler(m_rx_frame_asm);
214 EXPECT_EQ(0, onwire_bl.length());
215 EXPECT_EQ(TestFrame::tag, rx_tag);
216 EXPECT_EQ(m_rx_frame_asm.get_num_segments(), rx_segment_bls.size());
217
218 auto rx_frame = TestFrame::Decode(rx_segment_bls);
219 EXPECT_TRUE(m_header.contents_equal(rx_frame.header()));
220 EXPECT_TRUE(m_front.contents_equal(rx_frame.front()));
221 EXPECT_TRUE(m_middle.contents_equal(rx_frame.middle()));
222 EXPECT_TRUE(m_data.contents_equal(rx_frame.data()));
223 }
224
225 ceph::crypto::onwire::rxtx_t m_tx_crypto;
226 ceph::crypto::onwire::rxtx_t m_rx_crypto;
227 FrameAssembler m_tx_frame_asm;
228 FrameAssembler m_rx_frame_asm;
229
230 const bufferlist m_header;
231 const bufferlist m_front;
232 const bufferlist m_middle;
233 const bufferlist m_data;
234 };
235
236 class RoundTripTest : public RoundTripTestBase {};
237
238 TEST_P(RoundTripTest, Basic) {
239 test_round_trip();
240 }
241
242 TEST_P(RoundTripTest, Reuse) {
243 for (int i = 0; i < 3; i++) {
244 test_round_trip();
245 }
246 }
247
248 static const round_trip_instance_t round_trip_instances[] = {
249 // first segment is empty
250 { 0, 0, 0, 0, 1, {{32, 0, 17, 0, 0, 0},
251 {32, 0, 32, 0, 0, 0},
252 {32, 0, 0, 0, 0, 0},
253 {96, 0, 0, 0, 0, 0}}},
254 { 0, 0, 0, 303, 4, {{32, 0, 0, 0, 303, 17},
255 {32, 0, 0, 0, 304, 32},
256 {32, 0, 0, 0, 303, 13},
257 {96, 0, 0, 0, 304, 32}}},
258 { 0, 0, 202, 0, 3, {{32, 0, 0, 202, 17, 0},
259 {32, 0, 0, 208, 32, 0},
260 {32, 0, 0, 202, 13, 0},
261 {96, 0, 0, 208, 32, 0}}},
262 { 0, 0, 202, 303, 4, {{32, 0, 0, 202, 303, 17},
263 {32, 0, 0, 208, 304, 32},
264 {32, 0, 0, 202, 303, 13},
265 {96, 0, 0, 208, 304, 32}}},
266 { 0, 101, 0, 0, 2, {{32, 0, 101, 17, 0, 0},
267 {32, 0, 112, 32, 0, 0},
268 {32, 0, 101, 13, 0, 0},
269 {96, 0, 112, 32, 0, 0}}},
270 { 0, 101, 0, 303, 4, {{32, 0, 101, 0, 303, 17},
271 {32, 0, 112, 0, 304, 32},
272 {32, 0, 101, 0, 303, 13},
273 {96, 0, 112, 0, 304, 32}}},
274 { 0, 101, 202, 0, 3, {{32, 0, 101, 202, 17, 0},
275 {32, 0, 112, 208, 32, 0},
276 {32, 0, 101, 202, 13, 0},
277 {96, 0, 112, 208, 32, 0}}},
278 { 0, 101, 202, 303, 4, {{32, 0, 101, 202, 303, 17},
279 {32, 0, 112, 208, 304, 32},
280 {32, 0, 101, 202, 303, 13},
281 {96, 0, 112, 208, 304, 32}}},
282
283 // first segment is fully inlined, inline buffer is not full
284 { 1, 0, 0, 0, 1, {{32, 1, 17, 0, 0, 0},
285 {32, 16, 32, 0, 0, 0},
286 {32, 5, 0, 0, 0, 0},
287 {96, 0, 0, 0, 0, 0}}},
288 { 1, 0, 0, 303, 4, {{32, 1, 0, 0, 303, 17},
289 {32, 16, 0, 0, 304, 32},
290 {32, 5, 0, 0, 303, 13},
291 {96, 0, 0, 0, 304, 32}}},
292 { 1, 0, 202, 0, 3, {{32, 1, 0, 202, 17, 0},
293 {32, 16, 0, 208, 32, 0},
294 {32, 5, 0, 202, 13, 0},
295 {96, 0, 0, 208, 32, 0}}},
296 { 1, 0, 202, 303, 4, {{32, 1, 0, 202, 303, 17},
297 {32, 16, 0, 208, 304, 32},
298 {32, 5, 0, 202, 303, 13},
299 {96, 0, 0, 208, 304, 32}}},
300 { 1, 101, 0, 0, 2, {{32, 1, 101, 17, 0, 0},
301 {32, 16, 112, 32, 0, 0},
302 {32, 5, 101, 13, 0, 0},
303 {96, 0, 112, 32, 0, 0}}},
304 { 1, 101, 0, 303, 4, {{32, 1, 101, 0, 303, 17},
305 {32, 16, 112, 0, 304, 32},
306 {32, 5, 101, 0, 303, 13},
307 {96, 0, 112, 0, 304, 32}}},
308 { 1, 101, 202, 0, 3, {{32, 1, 101, 202, 17, 0},
309 {32, 16, 112, 208, 32, 0},
310 {32, 5, 101, 202, 13, 0},
311 {96, 0, 112, 208, 32, 0}}},
312 { 1, 101, 202, 303, 4, {{32, 1, 101, 202, 303, 17},
313 {32, 16, 112, 208, 304, 32},
314 {32, 5, 101, 202, 303, 13},
315 {96, 0, 112, 208, 304, 32}}},
316
317 // first segment is fully inlined, inline buffer is full
318 {48, 0, 0, 0, 1, {{32, 48, 17, 0, 0, 0},
319 {32, 48, 32, 0, 0, 0},
320 {32, 52, 0, 0, 0, 0},
321 {96, 0, 0, 0, 0, 0}}},
322 {48, 0, 0, 303, 4, {{32, 48, 0, 0, 303, 17},
323 {32, 48, 0, 0, 304, 32},
324 {32, 52, 0, 0, 303, 13},
325 {96, 0, 0, 0, 304, 32}}},
326 {48, 0, 202, 0, 3, {{32, 48, 0, 202, 17, 0},
327 {32, 48, 0, 208, 32, 0},
328 {32, 52, 0, 202, 13, 0},
329 {96, 0, 0, 208, 32, 0}}},
330 {48, 0, 202, 303, 4, {{32, 48, 0, 202, 303, 17},
331 {32, 48, 0, 208, 304, 32},
332 {32, 52, 0, 202, 303, 13},
333 {96, 0, 0, 208, 304, 32}}},
334 {48, 101, 0, 0, 2, {{32, 48, 101, 17, 0, 0},
335 {32, 48, 112, 32, 0, 0},
336 {32, 52, 101, 13, 0, 0},
337 {96, 0, 112, 32, 0, 0}}},
338 {48, 101, 0, 303, 4, {{32, 48, 101, 0, 303, 17},
339 {32, 48, 112, 0, 304, 32},
340 {32, 52, 101, 0, 303, 13},
341 {96, 0, 112, 0, 304, 32}}},
342 {48, 101, 202, 0, 3, {{32, 48, 101, 202, 17, 0},
343 {32, 48, 112, 208, 32, 0},
344 {32, 52, 101, 202, 13, 0},
345 {96, 0, 112, 208, 32, 0}}},
346 {48, 101, 202, 303, 4, {{32, 48, 101, 202, 303, 17},
347 {32, 48, 112, 208, 304, 32},
348 {32, 52, 101, 202, 303, 13},
349 {96, 0, 112, 208, 304, 32}}},
350
351 // first segment is partially inlined
352 {49, 0, 0, 0, 1, {{32, 49, 17, 0, 0, 0},
353 {32, 64, 32, 0, 0, 0},
354 {32, 53, 0, 0, 0, 0},
355 {96, 32, 0, 0, 0, 0}}},
356 {49, 0, 0, 303, 4, {{32, 49, 0, 0, 303, 17},
357 {32, 64, 0, 0, 304, 32},
358 {32, 53, 0, 0, 303, 13},
359 {96, 32, 0, 0, 304, 32}}},
360 {49, 0, 202, 0, 3, {{32, 49, 0, 202, 17, 0},
361 {32, 64, 0, 208, 32, 0},
362 {32, 53, 0, 202, 13, 0},
363 {96, 32, 0, 208, 32, 0}}},
364 {49, 0, 202, 303, 4, {{32, 49, 0, 202, 303, 17},
365 {32, 64, 0, 208, 304, 32},
366 {32, 53, 0, 202, 303, 13},
367 {96, 32, 0, 208, 304, 32}}},
368 {49, 101, 0, 0, 2, {{32, 49, 101, 17, 0, 0},
369 {32, 64, 112, 32, 0, 0},
370 {32, 53, 101, 13, 0, 0},
371 {96, 32, 112, 32, 0, 0}}},
372 {49, 101, 0, 303, 4, {{32, 49, 101, 0, 303, 17},
373 {32, 64, 112, 0, 304, 32},
374 {32, 53, 101, 0, 303, 13},
375 {96, 32, 112, 0, 304, 32}}},
376 {49, 101, 202, 0, 3, {{32, 49, 101, 202, 17, 0},
377 {32, 64, 112, 208, 32, 0},
378 {32, 53, 101, 202, 13, 0},
379 {96, 32, 112, 208, 32, 0}}},
380 {49, 101, 202, 303, 4, {{32, 49, 101, 202, 303, 17},
381 {32, 64, 112, 208, 304, 32},
382 {32, 53, 101, 202, 303, 13},
383 {96, 32, 112, 208, 304, 32}}},
384 };
385
386 INSTANTIATE_TEST_SUITE_P(
387 RoundTripTests, RoundTripTest, ::testing::Combine(
388 ::testing::ValuesIn(round_trip_instances),
389 ::testing::ValuesIn(modes)));
390
391 class RoundTripPerfTest : public RoundTripTestBase {};
392
393 TEST_P(RoundTripPerfTest, DISABLED_Basic) {
394 for (int i = 0; i < 100000; i++) {
395 auto tx_frame = TestFrame::Encode(m_header, m_front, m_middle, m_data);
396 auto onwire_bl = tx_frame.get_buffer(m_tx_frame_asm);
397
398 Tag rx_tag;
399 segment_bls_t rx_segment_bls;
400 ASSERT_TRUE(disassemble_frame(m_rx_frame_asm, onwire_bl, rx_tag,
401 rx_segment_bls));
402 }
403 }
404
405 static const round_trip_instance_t round_trip_perf_instances[] = {
406 {41, 250, 0, 0, 2, {{32, 41, 250, 17, 0, 0},
407 {32, 48, 256, 32, 0, 0},
408 {32, 45, 250, 13, 0, 0},
409 {96, 0, 256, 32, 0, 0}}},
410 {41, 250, 0, 512, 4, {{32, 41, 250, 0, 512, 17},
411 {32, 48, 256, 0, 512, 32},
412 {32, 45, 250, 0, 512, 13},
413 {96, 0, 256, 0, 512, 32}}},
414 {41, 250, 0, 4096, 4, {{32, 41, 250, 0, 4096, 17},
415 {32, 48, 256, 0, 4096, 32},
416 {32, 45, 250, 0, 4096, 13},
417 {96, 0, 256, 0, 4096, 32}}},
418 {41, 250, 0, 32768, 4, {{32, 41, 250, 0, 32768, 17},
419 {32, 48, 256, 0, 32768, 32},
420 {32, 45, 250, 0, 32768, 13},
421 {96, 0, 256, 0, 32768, 32}}},
422 {41, 250, 0, 131072, 4, {{32, 41, 250, 0, 131072, 17},
423 {32, 48, 256, 0, 131072, 32},
424 {32, 45, 250, 0, 131072, 13},
425 {96, 0, 256, 0, 131072, 32}}},
426 {41, 250, 0, 4194304, 4, {{32, 41, 250, 0, 4194304, 17},
427 {32, 48, 256, 0, 4194304, 32},
428 {32, 45, 250, 0, 4194304, 13},
429 {96, 0, 256, 0, 4194304, 32}}},
430 };
431
432 INSTANTIATE_TEST_SUITE_P(
433 RoundTripPerfTests, RoundTripPerfTest, ::testing::Combine(
434 ::testing::ValuesIn(round_trip_perf_instances),
435 ::testing::ValuesIn(modes)));
436
437 } // namespace ceph::msgr::v2
438
439 int main(int argc, char* argv[]) {
440 vector<const char*> args;
441 argv_to_vec(argc, (const char**)argv, args);
442
443 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
444 CODE_ENVIRONMENT_UTILITY,
445 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
446 common_init_finish(g_ceph_context);
447
448 ::testing::InitGoogleTest(&argc, argv);
449 return RUN_ALL_TESTS();
450 }