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"
7 #include "compression_onwire.h"
12 #include <boost/container/static_vector.hpp>
15 * Protocol V2 Frame Structures
17 * Documentation in: doc/dev/msgr2.rst
20 namespace ceph::msgr::v2
{
22 // We require these features from any peer, period, in order to encode
23 // a entity_addrvec_t.
24 const uint64_t msgr2_required
= CEPH_FEATUREMASK_MSG_ADDR2
;
26 // We additionally assume the peer has the below features *purely for
27 // the purpose of encoding the frames themselves*. The only complex
28 // types in the frames are entity_addr_t and entity_addrvec_t, and we
29 // specifically want the peer to understand the (new in nautilus)
30 // TYPE_ANY. We treat narrow this assumption to frames because we
31 // expect there may be future clients (the kernel) that understand
32 // msgr v2 and understand this encoding but don't necessarily have
33 // everything else that SERVER_NAUTILUS implies. Yes, a fresh feature
34 // bit would be a cleaner approach, but those are scarce these days.
35 const uint64_t msgr2_frame_assumed
=
37 CEPH_FEATUREMASK_SERVER_NAUTILUS
;
39 enum class Tag
: __u8
{
49 IDENT_MISSING_FEATURES
,
65 // TODO: this will be dropped with support for `allocation policies`.
66 // We need them because of the rx_buffers zero-copy optimization.
67 static constexpr __u16 PAGE_SIZE_ALIGNMENT
= 4096;
69 static constexpr __u16 DEFAULT_ALIGNMENT
= sizeof(void *);
73 } __attribute__((packed
));
77 static constexpr std::size_t HEADER
= 0;
78 static constexpr std::size_t FRONT
= 1;
79 static constexpr std::size_t MIDDLE
= 2;
80 static constexpr std::size_t DATA
= 3;
84 static constexpr std::size_t PAYLOAD
= 0;
88 static constexpr uint8_t CRYPTO_BLOCK_SIZE
{ 16 };
90 static constexpr std::size_t MAX_NUM_SEGMENTS
= 4;
92 // V2 preamble consists of one or more preamble blocks depending on
93 // the number of segments a particular frame needs. Each block holds
94 // up to MAX_NUM_SEGMENTS segments and has its own CRC.
96 // XXX: currently the multi-segment facility is NOT implemented.
97 struct preamble_block_t
{
98 // Tag. For multi-segmented frames the value is the same
99 // between subsequent preamble blocks.
102 // Number of segments to go in entire frame. First preable block has
103 // set this to just #segments, second #segments - MAX_NUM_SEGMENTS,
104 // third to #segments - MAX_NUM_SEGMENTS and so on.
107 segment_t segments
[MAX_NUM_SEGMENTS
];
112 // CRC32 for this single preamble block.
114 } __attribute__((packed
));
115 static_assert(sizeof(preamble_block_t
) % CRYPTO_BLOCK_SIZE
== 0);
116 static_assert(std::is_standard_layout
<preamble_block_t
>::value
);
118 struct epilogue_crc_rev0_block_t
{
119 __u8 late_flags
; // FRAME_LATE_FLAG_ABORTED
120 ceph_le32 crc_values
[MAX_NUM_SEGMENTS
];
121 } __attribute__((packed
));
122 static_assert(std::is_standard_layout_v
<epilogue_crc_rev0_block_t
>);
124 struct epilogue_crc_rev1_block_t
{
125 __u8 late_status
; // FRAME_LATE_STATUS_*
126 ceph_le32 crc_values
[MAX_NUM_SEGMENTS
- 1];
127 } __attribute__((packed
));
128 static_assert(std::is_standard_layout_v
<epilogue_crc_rev1_block_t
>);
130 struct epilogue_secure_rev0_block_t
{
131 __u8 late_flags
; // FRAME_LATE_FLAG_ABORTED
132 __u8 padding
[CRYPTO_BLOCK_SIZE
- sizeof(late_flags
)];
133 } __attribute__((packed
));
134 static_assert(sizeof(epilogue_secure_rev0_block_t
) % CRYPTO_BLOCK_SIZE
== 0);
135 static_assert(std::is_standard_layout_v
<epilogue_secure_rev0_block_t
>);
137 // epilogue_secure_rev0_block_t with late_flags changed to late_status
138 struct epilogue_secure_rev1_block_t
{
139 __u8 late_status
; // FRAME_LATE_STATUS_*
140 __u8 padding
[CRYPTO_BLOCK_SIZE
- sizeof(late_status
)];
141 } __attribute__((packed
));
142 static_assert(sizeof(epilogue_secure_rev1_block_t
) % CRYPTO_BLOCK_SIZE
== 0);
143 static_assert(std::is_standard_layout_v
<epilogue_secure_rev1_block_t
>);
145 static constexpr uint32_t FRAME_CRC_SIZE
= 4;
146 static constexpr uint32_t FRAME_PREAMBLE_INLINE_SIZE
= 48;
147 static_assert(FRAME_PREAMBLE_INLINE_SIZE
% CRYPTO_BLOCK_SIZE
== 0);
148 // just for performance, nothing should break otherwise
149 static_assert(sizeof(ceph_msg_header2
) <= FRAME_PREAMBLE_INLINE_SIZE
);
150 static constexpr uint32_t FRAME_PREAMBLE_WITH_INLINE_SIZE
=
151 sizeof(preamble_block_t
) + FRAME_PREAMBLE_INLINE_SIZE
;
153 // A frame can be aborted by the sender after transmitting the
154 // preamble and the first segment. The remainder of the frame
155 // is filled with zeros, up until the epilogue.
157 // This flag is for msgr2.0. Note that in crc mode, late_flags
158 // is not covered by any crc -- a single bit flip can result in
159 // a completed frame being dropped or in an aborted frame with
160 // garbage segment payloads being dispatched.
161 #define FRAME_LATE_FLAG_ABORTED (1<<0)
163 // For msgr2.1, FRAME_LATE_STATUS_ABORTED has the same meaning
164 // as FRAME_LATE_FLAG_ABORTED and late_status replaces late_flags.
165 // Bit error detection in crc mode is achieved by using a 4-bit
166 // nibble per flag with two code words that are far apart in terms
167 // of Hamming Distance (HD=4, same as provided by CRC32-C for
168 // input lengths over ~5K).
169 #define FRAME_LATE_STATUS_ABORTED 0x1
170 #define FRAME_LATE_STATUS_COMPLETE 0xe
171 #define FRAME_LATE_STATUS_ABORTED_MASK 0xf
173 #define FRAME_LATE_STATUS_RESERVED_TRUE 0x10
174 #define FRAME_LATE_STATUS_RESERVED_FALSE 0xe0
175 #define FRAME_LATE_STATUS_RESERVED_MASK 0xf0
177 // For msgr 2.1, FRAME_EARLY_X flags are sent as part of epilogue.
179 // This flag indicates whether frame segments have been compressed by
180 // sender, and used in segments' disassemblig phase.
181 #define FRAME_EARLY_DATA_COMPRESSED 0X1
183 struct FrameError
: std::runtime_error
{
184 using runtime_error::runtime_error
;
187 class FrameAssembler
{
189 // crypto must be non-null
190 FrameAssembler(const ceph::crypto::onwire::rxtx_t
* crypto
, bool is_rev1
,
191 bool with_data_crc
, const ceph::compression::onwire::rxtx_t
* compression
)
192 : m_crypto(crypto
), m_is_rev1(is_rev1
), m_with_data_crc(with_data_crc
),
193 m_compression(compression
) {}
195 void set_is_rev1(bool is_rev1
) {
205 size_t get_num_segments() const {
206 ceph_assert(!m_descs
.empty());
207 return m_descs
.size();
210 uint32_t get_segment_logical_len(size_t seg_idx
) const {
211 ceph_assert(seg_idx
< m_descs
.size());
212 return m_descs
[seg_idx
].logical_len
;
215 uint16_t get_segment_align(size_t seg_idx
) const {
216 ceph_assert(seg_idx
< m_descs
.size());
217 return m_descs
[seg_idx
].align
;
223 // [preamble inline buffer + auth tag -- only in msgr2.1 secure mode]
225 // The preamble is generated unconditionally.
227 // In msgr2.1 secure mode, the first segment is inlined into the
228 // preamble inline buffer, either fully or partially.
229 uint32_t get_preamble_onwire_len() const {
230 if (m_is_rev1
&& m_crypto
->rx
) {
231 return FRAME_PREAMBLE_WITH_INLINE_SIZE
+ get_auth_tag_len();
233 return sizeof(preamble_block_t
);
239 // [zero padding -- only in secure mode]
240 // [crc or auth tag -- only in msgr2.1, only for the first segment]
242 // For an empty segment, nothing is generated. In msgr2.1 secure
243 // mode, if the first segment gets fully inlined into the preamble
244 // inline buffer, it is considered empty.
245 uint32_t get_segment_onwire_len(size_t seg_idx
) const {
246 ceph_assert(seg_idx
< m_descs
.size());
248 uint32_t padded_len
= get_segment_padded_len(seg_idx
);
249 if (m_is_rev1
&& seg_idx
== 0) {
250 if (padded_len
> FRAME_PREAMBLE_INLINE_SIZE
) {
251 return padded_len
+ get_auth_tag_len() - FRAME_PREAMBLE_INLINE_SIZE
;
257 if (m_is_rev1
&& seg_idx
== 0 && m_descs
[0].logical_len
> 0) {
258 return m_descs
[0].logical_len
+ FRAME_CRC_SIZE
;
260 return m_descs
[seg_idx
].logical_len
;
265 // epilogue_*_block_t
266 // [auth tag -- only in secure mode]
268 // For msgr2.0, the epilogue is generated unconditionally. In
269 // crc mode, it stores crcs for all segments; the preamble is
270 // covered by its own crc. In secure mode, the epilogue auth tag
271 // covers the whole frame.
273 // For msgr2.1, the epilogue is generated only if the frame has
274 // more than one segment (i.e. at least one of second to fourth
275 // segments is not empty). In crc mode, it stores crcs for
276 // second to fourh segments; the preamble and the first segment
277 // are covered by their own crcs. In secure mode, the epilogue
278 // auth tag covers second to fourth segments; the preamble and the
279 // first segment (if not fully inlined into the preamble inline
280 // buffer) are covered by their own auth tags.
282 // Note that the auth tag format is an implementation detail of a
283 // particular cipher. FrameAssembler is concerned only with where
284 // the auth tag is placed (at the end of the ciphertext) and how
285 // long it is (RxHandler::get_extra_size_at_final()). This is to
286 // provide room for other encryption algorithms: currently we use
287 // AES-128-GCM with 16-byte tags, but it is possible to switch to
288 // e.g. AES-128-CBC + HMAC-SHA512 without affecting the protocol
289 // (except for the cipher negotiation, of course).
291 // Additionally, each variant of the epilogue contains either
292 // late_flags or late_status field that directs handling of frames
293 // with more than one segment.
294 uint32_t get_epilogue_onwire_len() const {
295 ceph_assert(!m_descs
.empty());
296 if (m_is_rev1
&& m_descs
.size() == 1) {
300 return (m_is_rev1
? sizeof(epilogue_secure_rev1_block_t
) :
301 sizeof(epilogue_secure_rev0_block_t
)) + get_auth_tag_len();
303 return m_is_rev1
? sizeof(epilogue_crc_rev1_block_t
) :
304 sizeof(epilogue_crc_rev0_block_t
);
307 uint64_t get_frame_logical_len() const;
308 uint64_t get_frame_onwire_len() const;
310 bufferlist
assemble_frame(Tag tag
, bufferlist segment_bls
[],
311 const uint16_t segment_aligns
[],
312 size_t segment_count
);
314 Tag
disassemble_preamble(bufferlist
& preamble_bl
);
316 bool disassemble_segments(bufferlist
& preamble_bl
,
317 bufferlist segments_bls
[],
318 bufferlist
& epilogue_bl
) const;
321 struct segment_desc_t
{
322 uint32_t logical_len
;
326 uint32_t get_segment_padded_len(size_t seg_idx
) const {
327 return p2roundup
<uint32_t>(m_descs
[seg_idx
].logical_len
,
331 uint32_t get_auth_tag_len() const {
332 return m_crypto
->rx
->get_extra_size_at_final();
335 bool is_compressed() const {
336 return m_flags
& FRAME_EARLY_DATA_COMPRESSED
;
339 void asm_compress(bufferlist segment_bls
[]);
341 bufferlist
asm_crc_rev0(const preamble_block_t
& preamble
,
342 bufferlist segment_bls
[]) const;
343 bufferlist
asm_secure_rev0(const preamble_block_t
& preamble
,
344 bufferlist segment_bls
[]) const;
345 bufferlist
asm_crc_rev1(const preamble_block_t
& preamble
,
346 bufferlist segment_bls
[]) const;
347 bufferlist
asm_secure_rev1(const preamble_block_t
& preamble
,
348 bufferlist segment_bls
[]) const;
350 // Like msgr1, and unlike msgr2.0, msgr2.1 allows interpreting the
351 // first segment before reading in the rest of the frame.
353 // For msgr2.1 (set_is_rev1(true)), you may:
355 // - read in the first segment
356 // - call disassemble_first_segment()
357 // - use the contents of the first segment, for example to
358 // look up user-provided buffers based on ceph_msg_header2::tid
359 // - read in the remaining segments, possibly directly into
360 // user-provided buffers
361 // - read in epilogue
362 // - call disassemble_remaining_segments()
363 // - call disasm_all_decompress()
365 // For msgr2.0 (set_is_rev1(false)), disassemble_first_segment() is
366 // a noop. To accomodate, disassemble_remaining_segments() always
367 // takes all segments and skips over the first segment in msgr2.1
370 // - read in all segments
371 // - read in epilogue
372 // - call disassemble_remaining_segments()
373 // - call disasm_all_decompress()
375 // disassemble_remaining_segments() returns true if the frame is
376 // ready for dispatching, or false if it was aborted by the sender
377 // and must be dropped.
378 void disassemble_first_segment(bufferlist
& preamble_bl
,
379 bufferlist
& segment_bl
) const;
380 bool disassemble_remaining_segments(bufferlist segment_bls
[],
381 bufferlist
& epilogue_bl
) const;
382 void disassemble_decompress(bufferlist segment_bls
[]) const;
384 bool disasm_all_crc_rev0(bufferlist segment_bls
[],
385 bufferlist
& epilogue_bl
) const;
386 bool disasm_all_secure_rev0(bufferlist segment_bls
[],
387 bufferlist
& epilogue_bl
) const;
388 void disasm_first_crc_rev1(bufferlist
& preamble_bl
,
389 bufferlist
& segment_bl
) const;
390 bool disasm_remaining_crc_rev1(bufferlist segment_bls
[],
391 bufferlist
& epilogue_bl
) const;
392 void disasm_first_secure_rev1(bufferlist
& preamble_bl
,
393 bufferlist
& segment_bl
) const;
394 bool disasm_remaining_secure_rev1(bufferlist segment_bls
[],
395 bufferlist
& epilogue_bl
) const;
397 void fill_preamble(Tag tag
, preamble_block_t
& preamble
) const;
398 friend std::ostream
& operator<<(std::ostream
& os
,
399 const FrameAssembler
& frame_asm
);
401 boost::container::static_vector
<segment_desc_t
, MAX_NUM_SEGMENTS
> m_descs
;
403 const ceph::crypto::onwire::rxtx_t
* m_crypto
;
404 bool m_is_rev1
; // msgr2.1?
405 bool m_with_data_crc
;
406 const ceph::compression::onwire::rxtx_t
* m_compression
;
409 template <class T
, uint16_t... SegmentAlignmentVs
>
411 static constexpr size_t SegmentsNumV
= sizeof...(SegmentAlignmentVs
);
412 static_assert(SegmentsNumV
> 0 && SegmentsNumV
<= MAX_NUM_SEGMENTS
);
414 std::array
<ceph::bufferlist
, SegmentsNumV
> segments
;
417 static constexpr std::array
<uint16_t, SegmentsNumV
> alignments
{
418 SegmentAlignmentVs
...
422 ceph::bufferlist
get_buffer(FrameAssembler
& tx_frame_asm
) {
423 auto bl
= tx_frame_asm
.assemble_frame(T::tag
, segments
.data(),
424 alignments
.data(), SegmentsNumV
);
425 ceph_assert(bl
.length() == tx_frame_asm
.get_frame_onwire_len());
430 // ControlFrames are used to manage transceiver state (like connections) and
431 // orchestrate transfers of MessageFrames. They use only single segment with
432 // marshalling facilities -- derived classes specify frame structure through
433 // Args pack while ControlFrame provides common encode/decode machinery.
434 template <class C
, typename
... Args
>
435 class ControlFrame
: public Frame
<C
, segment_t::DEFAULT_ALIGNMENT
/* single segment */> {
437 ceph::bufferlist
&get_payload_segment() {
438 return this->segments
[SegmentIndex::Control::PAYLOAD
];
441 // this tuple is only used when decoding values from a payload segment
442 std::tuple
<Args
...> _values
;
444 // FIXME: for now, we assume specific features for the purpoess of encoding
445 // the frames themselves (*not* messages in message frames!).
446 uint64_t features
= msgr2_frame_assumed
;
448 template <typename T
>
449 inline void _encode_payload_each(T
&t
) {
450 if constexpr (std::is_same
<T
, std::vector
<uint32_t> const>()) {
451 encode((uint32_t)t
.size(), this->get_payload_segment(), features
);
452 for (const auto &elem
: t
) {
453 encode(elem
, this->get_payload_segment(), features
);
456 encode(t
, this->get_payload_segment(), features
);
460 template <typename T
>
461 inline void _decode_payload_each(T
&t
, bufferlist::const_iterator
&ti
) const {
462 if constexpr (std::is_same
<T
, std::vector
<uint32_t>>()) {
466 for (uint32_t i
= 0; i
< size
; ++i
) {
474 template <std::size_t... Is
>
475 inline void _decode_payload(bufferlist::const_iterator
&ti
,
476 std::index_sequence
<Is
...>) const {
477 (_decode_payload_each((Args
&)std::get
<Is
>(_values
), ti
), ...);
480 template <std::size_t N
>
481 inline decltype(auto) get_val() {
482 return std::get
<N
>(_values
);
486 : Frame
<C
, segment_t::DEFAULT_ALIGNMENT
/* single segment */>() {
489 void _encode(const Args
&... args
) {
490 (_encode_payload_each(args
), ...);
493 void _decode(const ceph::bufferlist
&bl
) {
494 auto ti
= bl
.cbegin();
495 _decode_payload(ti
, std::index_sequence_for
<Args
...>());
499 static C
Encode(const Args
&... args
) {
505 static C
Decode(const ceph::bufferlist
&payload
) {
512 struct HelloFrame
: public ControlFrame
<HelloFrame
,
513 uint8_t, // entity type
514 entity_addr_t
> { // peer address
515 static const Tag tag
= Tag::HELLO
;
516 using ControlFrame::Encode
;
517 using ControlFrame::Decode
;
519 inline uint8_t &entity_type() { return get_val
<0>(); }
520 inline entity_addr_t
&peer_addr() { return get_val
<1>(); }
523 using ControlFrame::ControlFrame
;
526 struct AuthRequestFrame
: public ControlFrame
<AuthRequestFrame
,
527 uint32_t, // auth method
528 std::vector
<uint32_t>, // preferred modes
529 bufferlist
> { // auth payload
530 static const Tag tag
= Tag::AUTH_REQUEST
;
531 using ControlFrame::Encode
;
532 using ControlFrame::Decode
;
534 inline uint32_t &method() { return get_val
<0>(); }
535 inline std::vector
<uint32_t> &preferred_modes() { return get_val
<1>(); }
536 inline bufferlist
&auth_payload() { return get_val
<2>(); }
539 using ControlFrame::ControlFrame
;
542 struct AuthBadMethodFrame
: public ControlFrame
<AuthBadMethodFrame
,
545 std::vector
<uint32_t>, // allowed methods
546 std::vector
<uint32_t>> { // allowed modes
547 static const Tag tag
= Tag::AUTH_BAD_METHOD
;
548 using ControlFrame::Encode
;
549 using ControlFrame::Decode
;
551 inline uint32_t &method() { return get_val
<0>(); }
552 inline int32_t &result() { return get_val
<1>(); }
553 inline std::vector
<uint32_t> &allowed_methods() { return get_val
<2>(); }
554 inline std::vector
<uint32_t> &allowed_modes() { return get_val
<3>(); }
557 using ControlFrame::ControlFrame
;
560 struct AuthReplyMoreFrame
: public ControlFrame
<AuthReplyMoreFrame
,
561 bufferlist
> { // auth payload
562 static const Tag tag
= Tag::AUTH_REPLY_MORE
;
563 using ControlFrame::Encode
;
564 using ControlFrame::Decode
;
566 inline bufferlist
&auth_payload() { return get_val
<0>(); }
569 using ControlFrame::ControlFrame
;
572 struct AuthRequestMoreFrame
: public ControlFrame
<AuthRequestMoreFrame
,
573 bufferlist
> { // auth payload
574 static const Tag tag
= Tag::AUTH_REQUEST_MORE
;
575 using ControlFrame::Encode
;
576 using ControlFrame::Decode
;
578 inline bufferlist
&auth_payload() { return get_val
<0>(); }
581 using ControlFrame::ControlFrame
;
584 struct AuthDoneFrame
: public ControlFrame
<AuthDoneFrame
,
585 uint64_t, // global id
586 uint32_t, // connection mode
587 bufferlist
> { // auth method payload
588 static const Tag tag
= Tag::AUTH_DONE
;
589 using ControlFrame::Encode
;
590 using ControlFrame::Decode
;
592 inline uint64_t &global_id() { return get_val
<0>(); }
593 inline uint32_t &con_mode() { return get_val
<1>(); }
594 inline bufferlist
&auth_payload() { return get_val
<2>(); }
597 using ControlFrame::ControlFrame
;
600 struct AuthSignatureFrame
601 : public ControlFrame
<AuthSignatureFrame
,
603 static const Tag tag
= Tag::AUTH_SIGNATURE
;
604 using ControlFrame::Encode
;
605 using ControlFrame::Decode
;
607 inline sha256_digest_t
&signature() { return get_val
<0>(); }
610 using ControlFrame::ControlFrame
;
613 struct ClientIdentFrame
614 : public ControlFrame
<ClientIdentFrame
,
615 entity_addrvec_t
, // my addresses
616 entity_addr_t
, // target address
617 int64_t, // global_id
618 uint64_t, // global seq
619 uint64_t, // supported features
620 uint64_t, // required features
622 uint64_t> { // client cookie
623 static const Tag tag
= Tag::CLIENT_IDENT
;
624 using ControlFrame::Encode
;
625 using ControlFrame::Decode
;
627 inline entity_addrvec_t
&addrs() { return get_val
<0>(); }
628 inline entity_addr_t
&target_addr() { return get_val
<1>(); }
629 inline int64_t &gid() { return get_val
<2>(); }
630 inline uint64_t &global_seq() { return get_val
<3>(); }
631 inline uint64_t &supported_features() { return get_val
<4>(); }
632 inline uint64_t &required_features() { return get_val
<5>(); }
633 inline uint64_t &flags() { return get_val
<6>(); }
634 inline uint64_t &cookie() { return get_val
<7>(); }
637 using ControlFrame::ControlFrame
;
640 struct ServerIdentFrame
641 : public ControlFrame
<ServerIdentFrame
,
642 entity_addrvec_t
, // my addresses
643 int64_t, // global_id
644 uint64_t, // global seq
645 uint64_t, // supported features
646 uint64_t, // required features
648 uint64_t> { // server cookie
649 static const Tag tag
= Tag::SERVER_IDENT
;
650 using ControlFrame::Encode
;
651 using ControlFrame::Decode
;
653 inline entity_addrvec_t
&addrs() { return get_val
<0>(); }
654 inline int64_t &gid() { return get_val
<1>(); }
655 inline uint64_t &global_seq() { return get_val
<2>(); }
656 inline uint64_t &supported_features() { return get_val
<3>(); }
657 inline uint64_t &required_features() { return get_val
<4>(); }
658 inline uint64_t &flags() { return get_val
<5>(); }
659 inline uint64_t &cookie() { return get_val
<6>(); }
662 using ControlFrame::ControlFrame
;
665 struct ReconnectFrame
666 : public ControlFrame
<ReconnectFrame
,
667 entity_addrvec_t
, // my addresses
668 uint64_t, // client cookie
669 uint64_t, // server cookie
670 uint64_t, // global sequence
671 uint64_t, // connect sequence
672 uint64_t> { // message sequence
673 static const Tag tag
= Tag::SESSION_RECONNECT
;
674 using ControlFrame::Encode
;
675 using ControlFrame::Decode
;
677 inline entity_addrvec_t
&addrs() { return get_val
<0>(); }
678 inline uint64_t &client_cookie() { return get_val
<1>(); }
679 inline uint64_t &server_cookie() { return get_val
<2>(); }
680 inline uint64_t &global_seq() { return get_val
<3>(); }
681 inline uint64_t &connect_seq() { return get_val
<4>(); }
682 inline uint64_t &msg_seq() { return get_val
<5>(); }
685 using ControlFrame::ControlFrame
;
688 struct ResetFrame
: public ControlFrame
<ResetFrame
,
689 bool> { // full reset
690 static const Tag tag
= Tag::SESSION_RESET
;
691 using ControlFrame::Encode
;
692 using ControlFrame::Decode
;
694 inline bool &full() { return get_val
<0>(); }
697 using ControlFrame::ControlFrame
;
700 struct RetryFrame
: public ControlFrame
<RetryFrame
,
701 uint64_t> { // connection seq
702 static const Tag tag
= Tag::SESSION_RETRY
;
703 using ControlFrame::Encode
;
704 using ControlFrame::Decode
;
706 inline uint64_t &connect_seq() { return get_val
<0>(); }
709 using ControlFrame::ControlFrame
;
712 struct RetryGlobalFrame
: public ControlFrame
<RetryGlobalFrame
,
713 uint64_t> { // global seq
714 static const Tag tag
= Tag::SESSION_RETRY_GLOBAL
;
715 using ControlFrame::Encode
;
716 using ControlFrame::Decode
;
718 inline uint64_t &global_seq() { return get_val
<0>(); }
721 using ControlFrame::ControlFrame
;
724 struct WaitFrame
: public ControlFrame
<WaitFrame
> {
725 static const Tag tag
= Tag::WAIT
;
726 using ControlFrame::Encode
;
727 using ControlFrame::Decode
;
730 using ControlFrame::ControlFrame
;
733 struct ReconnectOkFrame
: public ControlFrame
<ReconnectOkFrame
,
734 uint64_t> { // message seq
735 static const Tag tag
= Tag::SESSION_RECONNECT_OK
;
736 using ControlFrame::Encode
;
737 using ControlFrame::Decode
;
739 inline uint64_t &msg_seq() { return get_val
<0>(); }
742 using ControlFrame::ControlFrame
;
745 struct IdentMissingFeaturesFrame
746 : public ControlFrame
<IdentMissingFeaturesFrame
,
747 uint64_t> { // missing features mask
748 static const Tag tag
= Tag::IDENT_MISSING_FEATURES
;
749 using ControlFrame::Encode
;
750 using ControlFrame::Decode
;
752 inline uint64_t &features() { return get_val
<0>(); }
755 using ControlFrame::ControlFrame
;
758 struct KeepAliveFrame
: public ControlFrame
<KeepAliveFrame
,
759 utime_t
> { // timestamp
760 static const Tag tag
= Tag::KEEPALIVE2
;
761 using ControlFrame::Encode
;
762 using ControlFrame::Decode
;
764 static KeepAliveFrame
Encode() {
765 return KeepAliveFrame::Encode(ceph_clock_now());
768 inline utime_t
×tamp() { return get_val
<0>(); }
771 using ControlFrame::ControlFrame
;
774 struct KeepAliveFrameAck
: public ControlFrame
<KeepAliveFrameAck
,
775 utime_t
> { // ack timestamp
776 static const Tag tag
= Tag::KEEPALIVE2_ACK
;
777 using ControlFrame::Encode
;
778 using ControlFrame::Decode
;
780 inline utime_t
×tamp() { return get_val
<0>(); }
783 using ControlFrame::ControlFrame
;
786 struct AckFrame
: public ControlFrame
<AckFrame
,
787 uint64_t> { // message sequence
788 static const Tag tag
= Tag::ACK
;
789 using ControlFrame::Encode
;
790 using ControlFrame::Decode
;
792 inline uint64_t &seq() { return get_val
<0>(); }
795 using ControlFrame::ControlFrame
;
798 using segment_bls_t
=
799 boost::container::static_vector
<bufferlist
, MAX_NUM_SEGMENTS
>;
801 // This class is used for encoding/decoding header of the message frame.
802 // Body is processed almost independently with the sole junction point
803 // being the `extra_payload_len` passed to get_buffer().
804 struct MessageFrame
: public Frame
<MessageFrame
,
806 segment_t::DEFAULT_ALIGNMENT
,
807 segment_t::DEFAULT_ALIGNMENT
,
808 segment_t::DEFAULT_ALIGNMENT
,
809 segment_t::PAGE_SIZE_ALIGNMENT
> {
810 static const Tag tag
= Tag::MESSAGE
;
812 static MessageFrame
Encode(const ceph_msg_header2
&msg_header
,
813 const ceph::bufferlist
&front
,
814 const ceph::bufferlist
&middle
,
815 const ceph::bufferlist
&data
) {
817 f
.segments
[SegmentIndex::Msg::HEADER
].append(
818 reinterpret_cast<const char*>(&msg_header
), sizeof(msg_header
));
820 f
.segments
[SegmentIndex::Msg::FRONT
] = front
;
821 f
.segments
[SegmentIndex::Msg::MIDDLE
] = middle
;
822 f
.segments
[SegmentIndex::Msg::DATA
] = data
;
827 static MessageFrame
Decode(segment_bls_t
& recv_segments
) {
829 // transfer segments' bufferlists. If a MessageFrame contains less
830 // SegmentsNumV segments, the missing ones will be seen as zeroed.
831 for (__u8 idx
= 0; idx
< std::size(recv_segments
); idx
++) {
832 f
.segments
[idx
] = std::move(recv_segments
[idx
]);
837 inline const ceph_msg_header2
&header() {
838 auto& hdrbl
= segments
[SegmentIndex::Msg::HEADER
];
839 return reinterpret_cast<const ceph_msg_header2
&>(*hdrbl
.c_str());
842 ceph::bufferlist
&front() {
843 return segments
[SegmentIndex::Msg::FRONT
];
846 ceph::bufferlist
&middle() {
847 return segments
[SegmentIndex::Msg::MIDDLE
];
850 ceph::bufferlist
&data() {
851 return segments
[SegmentIndex::Msg::DATA
];
854 uint32_t front_len() const {
855 return segments
[SegmentIndex::Msg::FRONT
].length();
858 uint32_t middle_len() const {
859 return segments
[SegmentIndex::Msg::MIDDLE
].length();
862 uint32_t data_len() const {
863 return segments
[SegmentIndex::Msg::DATA
].length();
870 struct CompressionRequestFrame
: public ControlFrame
<CompressionRequestFrame
,
872 std::vector
<uint32_t>> { // preferred methods
873 static const Tag tag
= Tag::COMPRESSION_REQUEST
;
874 using ControlFrame::Encode
;
875 using ControlFrame::Decode
;
877 inline bool &is_compress() { return get_val
<0>(); }
878 inline std::vector
<uint32_t> &preferred_methods() { return get_val
<1>(); }
881 using ControlFrame::ControlFrame
;
884 struct CompressionDoneFrame
: public ControlFrame
<CompressionDoneFrame
,
886 uint32_t> { // method
887 static const Tag tag
= Tag::COMPRESSION_DONE
;
888 using ControlFrame::Encode
;
889 using ControlFrame::Decode
;
891 inline bool &is_compress() { return get_val
<0>(); }
892 inline uint32_t &method() { return get_val
<1>(); }
895 using ControlFrame::ControlFrame
;
898 } // namespace ceph::msgr::v2
900 #endif // _MSG_ASYNC_FRAMES_V2_