1 #ifndef _MSG_ASYNC_FRAMES_V2_
2 #define _MSG_ASYNC_FRAMES_V2_
4 #include "include/types.h"
5 #include "common/Clock.h"
6 #include "crypto_onwire.h"
11 * Protocol V2 Frame Structures
13 * Documentation in: doc/dev/msgr2.rst
16 namespace ceph::msgr::v2
{
18 // We require these features from any peer, period, in order to encode
19 // a entity_addrvec_t.
20 const uint64_t msgr2_required
= CEPH_FEATUREMASK_MSG_ADDR2
;
22 // We additionally assume the peer has the below features *purely for
23 // the purpose of encoding the frames themselves*. The only complex
24 // types in the frames are entity_addr_t and entity_addrvec_t, and we
25 // specifically want the peer to understand the (new in nautilus)
26 // TYPE_ANY. We treat narrow this assumption to frames because we
27 // expect there may be future clients (the kernel) that understand
28 // msgr v2 and understand this encoding but don't necessarily have
29 // everything else that SERVER_NAUTILUS implies. Yes, a fresh feature
30 // bit would be a cleaner approach, but those are scarce these days.
31 const uint64_t msgr2_frame_assumed
=
33 CEPH_FEATUREMASK_SERVER_NAUTILUS
;
35 enum class Tag
: __u8
{
45 IDENT_MISSING_FEATURES
,
59 // TODO: this will be dropped with support for `allocation policies`.
60 // We need them because of the rx_buffers zero-copy optimization.
61 static constexpr __u16 PAGE_SIZE_ALIGNMENT
= 4096;
63 static constexpr __u16 DEFAULT_ALIGNMENT
= sizeof(void *);
67 } __attribute__((packed
));
71 static constexpr std::size_t HEADER
= 0;
72 static constexpr std::size_t FRONT
= 1;
73 static constexpr std::size_t MIDDLE
= 2;
74 static constexpr std::size_t DATA
= 3;
78 static constexpr std::size_t PAYLOAD
= 0;
82 static constexpr uint8_t CRYPTO_BLOCK_SIZE
{ 16 };
84 static constexpr std::size_t MAX_NUM_SEGMENTS
= 4;
86 // V2 preamble consists of one or more preamble blocks depending on
87 // the number of segments a particular frame needs. Each block holds
88 // up to MAX_NUM_SEGMENTS segments and has its own CRC.
90 // XXX: currently the multi-segment facility is NOT implemented.
91 struct preamble_block_t
{
92 // Tag. For multi-segmented frames the value is the same
93 // between subsequent preamble blocks.
96 // Number of segments to go in entire frame. First preable block has
97 // set this to just #segments, second #segments - MAX_NUM_SEGMENTS,
98 // third to #segments - MAX_NUM_SEGMENTS and so on.
101 segment_t segments
[MAX_NUM_SEGMENTS
];
104 // CRC32 for this single preamble block.
106 } __attribute__((packed
));
107 static_assert(sizeof(preamble_block_t
) % CRYPTO_BLOCK_SIZE
== 0);
108 static_assert(std::is_standard_layout
<preamble_block_t
>::value
);
110 // Each Frame has an epilogue for integrity or authenticity validation.
111 // For plain mode it's quite straightforward - the structure stores up
112 // to MAX_NUM_SEGMENTS crc32 checksums, one per each segment.
113 // For secure mode things become very different. The fundamental thing
114 // is that epilogue format is **an implementation detail of particular
115 // cipher**. ProtocolV2 only knows:
116 // * where the data is placed (always at the end of ciphertext),
117 // * how long it is. RxHandler provides get_extra_size_at_final() but
118 // ProtocolV2 has NO WAY to alter this.
120 // The intention behind the contract is to provide flexibility of cipher
121 // selection. Currently AES in GCM mode is used and epilogue conveys its
122 // *auth tag* (following OpenSSL's terminology). However, it would be OK
123 // to switch to e.g. AES128-CBC + HMAC-SHA512 without affecting protocol
124 // (expect the cipher negotiation, of course).
126 // In addition to integrity/authenticity data each variant of epilogue
127 // conveys late_flags. The initial user of this field will be the late
128 // frame abortion facility.
129 struct epilogue_plain_block_t
{
131 ceph_le32 crc_values
[MAX_NUM_SEGMENTS
];
132 } __attribute__((packed
));
133 static_assert(std::is_standard_layout
<epilogue_plain_block_t
>::value
);
135 struct epilogue_secure_block_t
{
137 __u8 padding
[CRYPTO_BLOCK_SIZE
- sizeof(late_flags
)];
139 __u8 ciphers_private_data
[];
140 } __attribute__((packed
));
141 static_assert(sizeof(epilogue_secure_block_t
) % CRYPTO_BLOCK_SIZE
== 0);
142 static_assert(std::is_standard_layout
<epilogue_secure_block_t
>::value
);
145 static constexpr uint32_t FRAME_PREAMBLE_SIZE
= sizeof(preamble_block_t
);
146 static constexpr uint32_t FRAME_PLAIN_EPILOGUE_SIZE
=
147 sizeof(epilogue_plain_block_t
);
148 static constexpr uint32_t FRAME_SECURE_EPILOGUE_SIZE
=
149 sizeof(epilogue_secure_block_t
);
151 #define FRAME_FLAGS_LATEABRT (1<<0) /* frame was aborted after txing data */
153 static uint32_t segment_onwire_size(const uint32_t logical_size
)
155 return p2roundup
<uint32_t>(logical_size
, CRYPTO_BLOCK_SIZE
);
158 static inline ceph::bufferlist
segment_onwire_bufferlist(ceph::bufferlist
&& bl
)
160 const auto padding_size
= segment_onwire_size(bl
.length()) - bl
.length();
162 bl
.append_zero(padding_size
);
164 return std::move(bl
);
167 template <class T
, uint16_t... SegmentAlignmentVs
>
169 static constexpr size_t SegmentsNumV
= sizeof...(SegmentAlignmentVs
);
170 static_assert(SegmentsNumV
> 0 && SegmentsNumV
<= MAX_NUM_SEGMENTS
);
172 std::array
<ceph::bufferlist
, SegmentsNumV
> segments
;
175 static constexpr std::array
<uint16_t, SegmentsNumV
> alignments
{
176 SegmentAlignmentVs
...
178 ceph::bufferlist::contiguous_filler preamble_filler
;
180 __u8
calc_num_segments(const segment_t segments
[])
182 for (__u8 num
= SegmentsNumV
; num
> 0; num
--) {
183 if (segments
[num
-1].length
) {
187 // frame always has at least one segment.
191 // craft the main preamble. It's always present regardless of the number
192 // of segments message is composed from.
193 void fill_preamble() {
194 ceph_assert(std::size(segments
) <= MAX_NUM_SEGMENTS
);
196 preamble_block_t main_preamble
;
197 // FIPS zeroization audit 20191115: this memset is not security related.
198 ::memset(&main_preamble
, 0, sizeof(main_preamble
));
200 main_preamble
.tag
= static_cast<__u8
>(T::tag
);
201 ceph_assert(main_preamble
.tag
!= 0);
203 // implementation detail: the first bufferlist of Frame::segments carries
204 // space for preamble. This glueing isn't a part of the onwire format but
205 // just our private detail.
206 main_preamble
.segments
[0].length
=
207 segments
[0].length() - FRAME_PREAMBLE_SIZE
;
208 main_preamble
.segments
[0].alignment
= alignments
[0];
210 // there is no business in issuing frame without at least one segment
212 if constexpr(SegmentsNumV
> 1) {
213 for (__u8 idx
= 1; idx
< SegmentsNumV
; idx
++) {
214 main_preamble
.segments
[idx
].length
= segments
[idx
].length();
215 main_preamble
.segments
[idx
].alignment
= alignments
[idx
];
218 // calculate the number of non-empty segments.
219 // TODO: reorder segments to get DATA first
220 main_preamble
.num_segments
= calc_num_segments(main_preamble
.segments
);
223 ceph_crc32c(0, reinterpret_cast<unsigned char *>(&main_preamble
),
224 sizeof(main_preamble
) - sizeof(main_preamble
.crc
));
226 preamble_filler
.copy_in(sizeof(main_preamble
),
227 reinterpret_cast<const char *>(&main_preamble
));
230 template <size_t... Is
>
231 void reset_tx_handler(
232 ceph::crypto::onwire::rxtx_t
&session_stream_handlers
,
233 std::index_sequence
<Is
...>)
235 session_stream_handlers
.tx
->reset_tx_handler({ segments
[Is
].length()... });
239 ceph::bufferlist
get_buffer(
240 ceph::crypto::onwire::rxtx_t
&session_stream_handlers
)
243 if (session_stream_handlers
.tx
) {
244 // we're padding segments to biggest cipher's block size. Although
245 // AES-GCM can live without that as it's a stream cipher, we don't
246 // to be fixed to stream ciphers only.
247 for (auto& segment
: segments
) {
248 segment
= segment_onwire_bufferlist(std::move(segment
));
251 // let's cipher allocate one huge buffer for entire ciphertext.
253 session_stream_handlers
, std::make_index_sequence
<SegmentsNumV
>());
255 for (auto& segment
: segments
) {
256 if (segment
.length()) {
257 session_stream_handlers
.tx
->authenticated_encrypt_update(
262 // in secure mode we craft only the late_flags. Signature (for AES-GCM
263 // called auth tag) will be added by the cipher.
265 epilogue_secure_block_t epilogue
;
266 // FIPS zeroization audit 20191115: this memset is not security
268 ::memset(&epilogue
, 0, sizeof(epilogue
));
269 ceph::bufferlist epilogue_bl
;
270 epilogue_bl
.append(reinterpret_cast<const char*>(&epilogue
),
272 session_stream_handlers
.tx
->authenticated_encrypt_update(epilogue_bl
);
274 return session_stream_handlers
.tx
->authenticated_encrypt_final();
277 epilogue_plain_block_t epilogue
;
278 // FIPS zeroization audit 20191115: this memset is not security related.
279 ::memset(&epilogue
, 0, sizeof(epilogue
));
281 ceph::bufferlist::const_iterator
hdriter(&segments
.front(),
282 FRAME_PREAMBLE_SIZE
);
283 epilogue
.crc_values
[SegmentIndex::Control::PAYLOAD
] =
284 hdriter
.crc32c(hdriter
.get_remaining(), -1);
285 if constexpr(SegmentsNumV
> 1) {
286 for (__u8 idx
= 1; idx
< SegmentsNumV
; idx
++) {
287 epilogue
.crc_values
[idx
] = segments
[idx
].crc32c(-1);
291 ceph::bufferlist ret
;
292 for (auto& segment
: segments
) {
293 ret
.claim_append(segment
);
295 ret
.append(reinterpret_cast<const char*>(&epilogue
), sizeof(epilogue
));
301 : preamble_filler(segments
.front().append_hole(FRAME_PREAMBLE_SIZE
)) {
308 // ControlFrames are used to manage transceiver state (like connections) and
309 // orchestrate transfers of MessageFrames. They use only single segment with
310 // marshalling facilities -- derived classes specify frame structure through
311 // Args pack while ControlFrame provides common encode/decode machinery.
312 template <class C
, typename
... Args
>
313 class ControlFrame
: public Frame
<C
, segment_t::DEFAULT_ALIGNMENT
/* single segment */> {
315 ceph::bufferlist
&get_payload_segment() {
316 return this->segments
[SegmentIndex::Control::PAYLOAD
];
319 // this tuple is only used when decoding values from a payload segment
320 std::tuple
<Args
...> _values
;
322 // FIXME: for now, we assume specific features for the purpoess of encoding
323 // the frames themselves (*not* messages in message frames!).
324 uint64_t features
= msgr2_frame_assumed
;
326 template <typename T
>
327 inline void _encode_payload_each(T
&t
) {
328 if constexpr (std::is_same
<T
, std::vector
<uint32_t> const>()) {
329 encode((uint32_t)t
.size(), this->get_payload_segment(), features
);
330 for (const auto &elem
: t
) {
331 encode(elem
, this->get_payload_segment(), features
);
334 encode(t
, this->get_payload_segment(), features
);
338 template <typename T
>
339 inline void _decode_payload_each(T
&t
, bufferlist::const_iterator
&ti
) const {
340 if constexpr (std::is_same
<T
, std::vector
<uint32_t>>()) {
344 for (uint32_t i
= 0; i
< size
; ++i
) {
352 template <std::size_t... Is
>
353 inline void _decode_payload(bufferlist::const_iterator
&ti
,
354 std::index_sequence
<Is
...>) const {
355 (_decode_payload_each((Args
&)std::get
<Is
>(_values
), ti
), ...);
358 template <std::size_t N
>
359 inline decltype(auto) get_val() {
360 return std::get
<N
>(_values
);
364 : Frame
<C
, segment_t::DEFAULT_ALIGNMENT
/* single segment */>() {
367 void _encode(const Args
&... args
) {
368 (_encode_payload_each(args
), ...);
371 void _decode(const ceph::bufferlist
&bl
) {
372 auto ti
= bl
.cbegin();
373 _decode_payload(ti
, std::index_sequence_for
<Args
...>());
377 static C
Encode(const Args
&... args
) {
383 static C
Decode(const ceph::bufferlist
&payload
) {
390 struct HelloFrame
: public ControlFrame
<HelloFrame
,
391 uint8_t, // entity type
392 entity_addr_t
> { // peer address
393 static const Tag tag
= Tag::HELLO
;
394 using ControlFrame::Encode
;
395 using ControlFrame::Decode
;
397 inline uint8_t &entity_type() { return get_val
<0>(); }
398 inline entity_addr_t
&peer_addr() { return get_val
<1>(); }
401 using ControlFrame::ControlFrame
;
404 struct AuthRequestFrame
: public ControlFrame
<AuthRequestFrame
,
405 uint32_t, // auth method
406 vector
<uint32_t>, // preferred modes
407 bufferlist
> { // auth payload
408 static const Tag tag
= Tag::AUTH_REQUEST
;
409 using ControlFrame::Encode
;
410 using ControlFrame::Decode
;
412 inline uint32_t &method() { return get_val
<0>(); }
413 inline vector
<uint32_t> &preferred_modes() { return get_val
<1>(); }
414 inline bufferlist
&auth_payload() { return get_val
<2>(); }
417 using ControlFrame::ControlFrame
;
420 struct AuthBadMethodFrame
: public ControlFrame
<AuthBadMethodFrame
,
423 std::vector
<uint32_t>, // allowed methods
424 std::vector
<uint32_t>> { // allowed modes
425 static const Tag tag
= Tag::AUTH_BAD_METHOD
;
426 using ControlFrame::Encode
;
427 using ControlFrame::Decode
;
429 inline uint32_t &method() { return get_val
<0>(); }
430 inline int32_t &result() { return get_val
<1>(); }
431 inline std::vector
<uint32_t> &allowed_methods() { return get_val
<2>(); }
432 inline std::vector
<uint32_t> &allowed_modes() { return get_val
<3>(); }
435 using ControlFrame::ControlFrame
;
438 struct AuthReplyMoreFrame
: public ControlFrame
<AuthReplyMoreFrame
,
439 bufferlist
> { // auth payload
440 static const Tag tag
= Tag::AUTH_REPLY_MORE
;
441 using ControlFrame::Encode
;
442 using ControlFrame::Decode
;
444 inline bufferlist
&auth_payload() { return get_val
<0>(); }
447 using ControlFrame::ControlFrame
;
450 struct AuthRequestMoreFrame
: public ControlFrame
<AuthRequestMoreFrame
,
451 bufferlist
> { // auth payload
452 static const Tag tag
= Tag::AUTH_REQUEST_MORE
;
453 using ControlFrame::Encode
;
454 using ControlFrame::Decode
;
456 inline bufferlist
&auth_payload() { return get_val
<0>(); }
459 using ControlFrame::ControlFrame
;
462 struct AuthDoneFrame
: public ControlFrame
<AuthDoneFrame
,
463 uint64_t, // global id
464 uint32_t, // connection mode
465 bufferlist
> { // auth method payload
466 static const Tag tag
= Tag::AUTH_DONE
;
467 using ControlFrame::Encode
;
468 using ControlFrame::Decode
;
470 inline uint64_t &global_id() { return get_val
<0>(); }
471 inline uint32_t &con_mode() { return get_val
<1>(); }
472 inline bufferlist
&auth_payload() { return get_val
<2>(); }
475 using ControlFrame::ControlFrame
;
478 struct AuthSignatureFrame
479 : public ControlFrame
<AuthSignatureFrame
,
481 static const Tag tag
= Tag::AUTH_SIGNATURE
;
482 using ControlFrame::Encode
;
483 using ControlFrame::Decode
;
485 inline sha256_digest_t
&signature() { return get_val
<0>(); }
488 using ControlFrame::ControlFrame
;
491 struct ClientIdentFrame
492 : public ControlFrame
<ClientIdentFrame
,
493 entity_addrvec_t
, // my addresses
494 entity_addr_t
, // target address
495 int64_t, // global_id
496 uint64_t, // global seq
497 uint64_t, // supported features
498 uint64_t, // required features
500 uint64_t> { // client cookie
501 static const Tag tag
= Tag::CLIENT_IDENT
;
502 using ControlFrame::Encode
;
503 using ControlFrame::Decode
;
505 inline entity_addrvec_t
&addrs() { return get_val
<0>(); }
506 inline entity_addr_t
&target_addr() { return get_val
<1>(); }
507 inline int64_t &gid() { return get_val
<2>(); }
508 inline uint64_t &global_seq() { return get_val
<3>(); }
509 inline uint64_t &supported_features() { return get_val
<4>(); }
510 inline uint64_t &required_features() { return get_val
<5>(); }
511 inline uint64_t &flags() { return get_val
<6>(); }
512 inline uint64_t &cookie() { return get_val
<7>(); }
515 using ControlFrame::ControlFrame
;
518 struct ServerIdentFrame
519 : public ControlFrame
<ServerIdentFrame
,
520 entity_addrvec_t
, // my addresses
521 int64_t, // global_id
522 uint64_t, // global seq
523 uint64_t, // supported features
524 uint64_t, // required features
526 uint64_t> { // server cookie
527 static const Tag tag
= Tag::SERVER_IDENT
;
528 using ControlFrame::Encode
;
529 using ControlFrame::Decode
;
531 inline entity_addrvec_t
&addrs() { return get_val
<0>(); }
532 inline int64_t &gid() { return get_val
<1>(); }
533 inline uint64_t &global_seq() { return get_val
<2>(); }
534 inline uint64_t &supported_features() { return get_val
<3>(); }
535 inline uint64_t &required_features() { return get_val
<4>(); }
536 inline uint64_t &flags() { return get_val
<5>(); }
537 inline uint64_t &cookie() { return get_val
<6>(); }
540 using ControlFrame::ControlFrame
;
543 struct ReconnectFrame
544 : public ControlFrame
<ReconnectFrame
,
545 entity_addrvec_t
, // my addresses
546 uint64_t, // client cookie
547 uint64_t, // server cookie
548 uint64_t, // global sequence
549 uint64_t, // connect sequence
550 uint64_t> { // message sequence
551 static const Tag tag
= Tag::SESSION_RECONNECT
;
552 using ControlFrame::Encode
;
553 using ControlFrame::Decode
;
555 inline entity_addrvec_t
&addrs() { return get_val
<0>(); }
556 inline uint64_t &client_cookie() { return get_val
<1>(); }
557 inline uint64_t &server_cookie() { return get_val
<2>(); }
558 inline uint64_t &global_seq() { return get_val
<3>(); }
559 inline uint64_t &connect_seq() { return get_val
<4>(); }
560 inline uint64_t &msg_seq() { return get_val
<5>(); }
563 using ControlFrame::ControlFrame
;
566 struct ResetFrame
: public ControlFrame
<ResetFrame
,
567 bool> { // full reset
568 static const Tag tag
= Tag::SESSION_RESET
;
569 using ControlFrame::Encode
;
570 using ControlFrame::Decode
;
572 inline bool &full() { return get_val
<0>(); }
575 using ControlFrame::ControlFrame
;
578 struct RetryFrame
: public ControlFrame
<RetryFrame
,
579 uint64_t> { // connection seq
580 static const Tag tag
= Tag::SESSION_RETRY
;
581 using ControlFrame::Encode
;
582 using ControlFrame::Decode
;
584 inline uint64_t &connect_seq() { return get_val
<0>(); }
587 using ControlFrame::ControlFrame
;
590 struct RetryGlobalFrame
: public ControlFrame
<RetryGlobalFrame
,
591 uint64_t> { // global seq
592 static const Tag tag
= Tag::SESSION_RETRY_GLOBAL
;
593 using ControlFrame::Encode
;
594 using ControlFrame::Decode
;
596 inline uint64_t &global_seq() { return get_val
<0>(); }
599 using ControlFrame::ControlFrame
;
602 struct WaitFrame
: public ControlFrame
<WaitFrame
> {
603 static const Tag tag
= Tag::WAIT
;
604 using ControlFrame::Encode
;
605 using ControlFrame::Decode
;
608 using ControlFrame::ControlFrame
;
611 struct ReconnectOkFrame
: public ControlFrame
<ReconnectOkFrame
,
612 uint64_t> { // message seq
613 static const Tag tag
= Tag::SESSION_RECONNECT_OK
;
614 using ControlFrame::Encode
;
615 using ControlFrame::Decode
;
617 inline uint64_t &msg_seq() { return get_val
<0>(); }
620 using ControlFrame::ControlFrame
;
623 struct IdentMissingFeaturesFrame
624 : public ControlFrame
<IdentMissingFeaturesFrame
,
625 uint64_t> { // missing features mask
626 static const Tag tag
= Tag::IDENT_MISSING_FEATURES
;
627 using ControlFrame::Encode
;
628 using ControlFrame::Decode
;
630 inline uint64_t &features() { return get_val
<0>(); }
633 using ControlFrame::ControlFrame
;
636 struct KeepAliveFrame
: public ControlFrame
<KeepAliveFrame
,
637 utime_t
> { // timestamp
638 static const Tag tag
= Tag::KEEPALIVE2
;
639 using ControlFrame::Encode
;
640 using ControlFrame::Decode
;
642 static KeepAliveFrame
Encode() {
643 return KeepAliveFrame::Encode(ceph_clock_now());
646 inline utime_t
×tamp() { return get_val
<0>(); }
649 using ControlFrame::ControlFrame
;
652 struct KeepAliveFrameAck
: public ControlFrame
<KeepAliveFrameAck
,
653 utime_t
> { // ack timestamp
654 static const Tag tag
= Tag::KEEPALIVE2_ACK
;
655 using ControlFrame::Encode
;
656 using ControlFrame::Decode
;
658 inline utime_t
×tamp() { return get_val
<0>(); }
661 using ControlFrame::ControlFrame
;
664 struct AckFrame
: public ControlFrame
<AckFrame
,
665 uint64_t> { // message sequence
666 static const Tag tag
= Tag::ACK
;
667 using ControlFrame::Encode
;
668 using ControlFrame::Decode
;
670 inline uint64_t &seq() { return get_val
<0>(); }
673 using ControlFrame::ControlFrame
;
676 // This class is used for encoding/decoding header of the message frame.
677 // Body is processed almost independently with the sole junction point
678 // being the `extra_payload_len` passed to get_buffer().
679 struct MessageFrame
: public Frame
<MessageFrame
,
681 segment_t::DEFAULT_ALIGNMENT
,
682 segment_t::DEFAULT_ALIGNMENT
,
683 segment_t::DEFAULT_ALIGNMENT
,
684 segment_t::PAGE_SIZE_ALIGNMENT
> {
691 static const Tag tag
= Tag::MESSAGE
;
693 static MessageFrame
Encode(const ceph_msg_header2
&msg_header
,
694 const ceph::bufferlist
&front
,
695 const ceph::bufferlist
&middle
,
696 const ceph::bufferlist
&data
) {
698 f
.segments
[SegmentIndex::Msg::HEADER
].append(
699 reinterpret_cast<const char*>(&msg_header
), sizeof(msg_header
));
701 f
.segments
[SegmentIndex::Msg::FRONT
] = front
;
702 f
.segments
[SegmentIndex::Msg::MIDDLE
] = middle
;
703 f
.segments
[SegmentIndex::Msg::DATA
] = data
;
708 using rx_segments_t
=
709 boost::container::static_vector
<ceph::bufferlist
,
710 ceph::msgr::v2::MAX_NUM_SEGMENTS
>;
711 static MessageFrame
Decode(rx_segments_t
&&recv_segments
) {
713 // transfer segments' bufferlists. If a MessageFrame contains less
714 // SegmentsNumV segments, the missing ones will be seen as zeroed.
715 for (__u8 idx
= 0; idx
< std::size(recv_segments
); idx
++) {
716 f
.segments
[idx
] = std::move(recv_segments
[idx
]);
721 inline const ceph_msg_header2
&header() {
722 auto& hdrbl
= segments
[SegmentIndex::Msg::HEADER
];
723 return reinterpret_cast<const ceph_msg_header2
&>(*hdrbl
.c_str());
726 ceph::bufferlist
&front() {
727 return segments
[SegmentIndex::Msg::FRONT
];
730 ceph::bufferlist
&middle() {
731 return segments
[SegmentIndex::Msg::MIDDLE
];
734 ceph::bufferlist
&data() {
735 return segments
[SegmentIndex::Msg::DATA
];
738 uint32_t front_len() const {
739 return segments
[SegmentIndex::Msg::FRONT
].length();
742 uint32_t middle_len() const {
743 return segments
[SegmentIndex::Msg::MIDDLE
].length();
746 uint32_t data_len() const {
747 return segments
[SegmentIndex::Msg::DATA
].length();
754 } // namespace ceph::msgr::v2
756 #endif // _MSG_ASYNC_FRAMES_V2_