]> git.proxmox.com Git - ceph.git/blob - ceph/src/msg/async/frames_v2.h
import quincy beta 17.1.0
[ceph.git] / ceph / src / msg / async / frames_v2.h
1 #ifndef _MSG_ASYNC_FRAMES_V2_
2 #define _MSG_ASYNC_FRAMES_V2_
3
4 #include "include/types.h"
5 #include "common/Clock.h"
6 #include "crypto_onwire.h"
7 #include "compression_onwire.h"
8 #include <array>
9 #include <iosfwd>
10 #include <utility>
11
12 #include <boost/container/static_vector.hpp>
13
14 /**
15 * Protocol V2 Frame Structures
16 *
17 * Documentation in: doc/dev/msgr2.rst
18 **/
19
20 namespace ceph::msgr::v2 {
21
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;
25
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 =
36 msgr2_required |
37 CEPH_FEATUREMASK_SERVER_NAUTILUS;
38
39 enum class Tag : __u8 {
40 HELLO = 1,
41 AUTH_REQUEST,
42 AUTH_BAD_METHOD,
43 AUTH_REPLY_MORE,
44 AUTH_REQUEST_MORE,
45 AUTH_DONE,
46 AUTH_SIGNATURE,
47 CLIENT_IDENT,
48 SERVER_IDENT,
49 IDENT_MISSING_FEATURES,
50 SESSION_RECONNECT,
51 SESSION_RESET,
52 SESSION_RETRY,
53 SESSION_RETRY_GLOBAL,
54 SESSION_RECONNECT_OK,
55 WAIT,
56 MESSAGE,
57 KEEPALIVE2,
58 KEEPALIVE2_ACK,
59 ACK,
60 COMPRESSION_REQUEST,
61 COMPRESSION_DONE
62 };
63
64 struct segment_t {
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;
68
69 static constexpr __u16 DEFAULT_ALIGNMENT = sizeof(void *);
70
71 ceph_le32 length;
72 ceph_le16 alignment;
73 } __attribute__((packed));
74
75 struct SegmentIndex {
76 struct Msg {
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;
81 };
82
83 struct Control {
84 static constexpr std::size_t PAYLOAD = 0;
85 };
86 };
87
88 static constexpr uint8_t CRYPTO_BLOCK_SIZE { 16 };
89
90 static constexpr std::size_t MAX_NUM_SEGMENTS = 4;
91
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.
95 //
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.
100 __u8 tag;
101
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.
105 __u8 num_segments;
106
107 segment_t segments[MAX_NUM_SEGMENTS];
108
109 __u8 flags;
110 __u8 _reserved;
111
112 // CRC32 for this single preamble block.
113 ceph_le32 crc;
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);
117
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>);
123
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>);
129
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>);
136
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>);
144
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;
152
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.
156 //
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)
162
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
172
173 #define FRAME_LATE_STATUS_RESERVED_TRUE 0x10
174 #define FRAME_LATE_STATUS_RESERVED_FALSE 0xe0
175 #define FRAME_LATE_STATUS_RESERVED_MASK 0xf0
176
177 // For msgr 2.1, FRAME_EARLY_X flags are sent as part of epilogue.
178 //
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
182
183 struct FrameError : std::runtime_error {
184 using runtime_error::runtime_error;
185 };
186
187 class FrameAssembler {
188 public:
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) {}
194
195 void set_is_rev1(bool is_rev1) {
196 m_descs.clear();
197 m_flags = 0;
198 m_is_rev1 = is_rev1;
199 }
200
201 bool get_is_rev1() {
202 return m_is_rev1;
203 }
204
205 size_t get_num_segments() const {
206 ceph_assert(!m_descs.empty());
207 return m_descs.size();
208 }
209
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;
213 }
214
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;
218 }
219
220 // Preamble:
221 //
222 // preamble_block_t
223 // [preamble inline buffer + auth tag -- only in msgr2.1 secure mode]
224 //
225 // The preamble is generated unconditionally.
226 //
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();
232 }
233 return sizeof(preamble_block_t);
234 }
235
236 // Segment:
237 //
238 // segment payload
239 // [zero padding -- only in secure mode]
240 // [crc or auth tag -- only in msgr2.1, only for the first segment]
241 //
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());
247 if (m_crypto->rx) {
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;
252 }
253 return 0;
254 }
255 return padded_len;
256 }
257 if (m_is_rev1 && seg_idx == 0 && m_descs[0].logical_len > 0) {
258 return m_descs[0].logical_len + FRAME_CRC_SIZE;
259 }
260 return m_descs[seg_idx].logical_len;
261 }
262
263 // Epilogue:
264 //
265 // epilogue_*_block_t
266 // [auth tag -- only in secure mode]
267 //
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.
272 //
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.
281 //
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).
290 //
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) {
297 return 0;
298 }
299 if (m_crypto->rx) {
300 return (m_is_rev1 ? sizeof(epilogue_secure_rev1_block_t) :
301 sizeof(epilogue_secure_rev0_block_t)) + get_auth_tag_len();
302 }
303 return m_is_rev1 ? sizeof(epilogue_crc_rev1_block_t) :
304 sizeof(epilogue_crc_rev0_block_t);
305 }
306
307 uint64_t get_frame_logical_len() const;
308 uint64_t get_frame_onwire_len() const;
309
310 bufferlist assemble_frame(Tag tag, bufferlist segment_bls[],
311 const uint16_t segment_aligns[],
312 size_t segment_count);
313
314 Tag disassemble_preamble(bufferlist& preamble_bl);
315
316 bool disassemble_segments(bufferlist& preamble_bl,
317 bufferlist segments_bls[],
318 bufferlist& epilogue_bl) const;
319
320 private:
321 struct segment_desc_t {
322 uint32_t logical_len;
323 uint16_t align;
324 };
325
326 uint32_t get_segment_padded_len(size_t seg_idx) const {
327 return p2roundup<uint32_t>(m_descs[seg_idx].logical_len,
328 CRYPTO_BLOCK_SIZE);
329 }
330
331 uint32_t get_auth_tag_len() const {
332 return m_crypto->rx->get_extra_size_at_final();
333 }
334
335 bool is_compressed() const {
336 return m_flags & FRAME_EARLY_DATA_COMPRESSED;
337 }
338
339 void asm_compress(bufferlist segment_bls[]);
340
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;
349
350 // Like msgr1, and unlike msgr2.0, msgr2.1 allows interpreting the
351 // first segment before reading in the rest of the frame.
352 //
353 // For msgr2.1 (set_is_rev1(true)), you may:
354 //
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()
364 //
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
368 // case. You must:
369 //
370 // - read in all segments
371 // - read in epilogue
372 // - call disassemble_remaining_segments()
373 // - call disasm_all_decompress()
374 //
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;
383
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;
396
397 void fill_preamble(Tag tag, preamble_block_t& preamble) const;
398 friend std::ostream& operator<<(std::ostream& os,
399 const FrameAssembler& frame_asm);
400
401 boost::container::static_vector<segment_desc_t, MAX_NUM_SEGMENTS> m_descs;
402 __u8 m_flags;
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;
407 };
408
409 template <class T, uint16_t... SegmentAlignmentVs>
410 struct Frame {
411 static constexpr size_t SegmentsNumV = sizeof...(SegmentAlignmentVs);
412 static_assert(SegmentsNumV > 0 && SegmentsNumV <= MAX_NUM_SEGMENTS);
413 protected:
414 std::array<ceph::bufferlist, SegmentsNumV> segments;
415
416 private:
417 static constexpr std::array<uint16_t, SegmentsNumV> alignments {
418 SegmentAlignmentVs...
419 };
420
421 public:
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());
426 return bl;
427 }
428 };
429
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 */> {
436 protected:
437 ceph::bufferlist &get_payload_segment() {
438 return this->segments[SegmentIndex::Control::PAYLOAD];
439 }
440
441 // this tuple is only used when decoding values from a payload segment
442 std::tuple<Args...> _values;
443
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;
447
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);
454 }
455 } else {
456 encode(t, this->get_payload_segment(), features);
457 }
458 }
459
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>>()) {
463 uint32_t size;
464 decode(size, ti);
465 t.resize(size);
466 for (uint32_t i = 0; i < size; ++i) {
467 decode(t[i], ti);
468 }
469 } else {
470 decode(t, ti);
471 }
472 }
473
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), ...);
478 }
479
480 template <std::size_t N>
481 inline decltype(auto) get_val() {
482 return std::get<N>(_values);
483 }
484
485 ControlFrame()
486 : Frame<C, segment_t::DEFAULT_ALIGNMENT /* single segment */>() {
487 }
488
489 void _encode(const Args &... args) {
490 (_encode_payload_each(args), ...);
491 }
492
493 void _decode(const ceph::bufferlist &bl) {
494 auto ti = bl.cbegin();
495 _decode_payload(ti, std::index_sequence_for<Args...>());
496 }
497
498 public:
499 static C Encode(const Args &... args) {
500 C c;
501 c._encode(args...);
502 return c;
503 }
504
505 static C Decode(const ceph::bufferlist &payload) {
506 C c;
507 c._decode(payload);
508 return c;
509 }
510 };
511
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;
518
519 inline uint8_t &entity_type() { return get_val<0>(); }
520 inline entity_addr_t &peer_addr() { return get_val<1>(); }
521
522 protected:
523 using ControlFrame::ControlFrame;
524 };
525
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;
533
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>(); }
537
538 protected:
539 using ControlFrame::ControlFrame;
540 };
541
542 struct AuthBadMethodFrame : public ControlFrame<AuthBadMethodFrame,
543 uint32_t, // method
544 int32_t, // result
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;
550
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>(); }
555
556 protected:
557 using ControlFrame::ControlFrame;
558 };
559
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;
565
566 inline bufferlist &auth_payload() { return get_val<0>(); }
567
568 protected:
569 using ControlFrame::ControlFrame;
570 };
571
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;
577
578 inline bufferlist &auth_payload() { return get_val<0>(); }
579
580 protected:
581 using ControlFrame::ControlFrame;
582 };
583
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;
591
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>(); }
595
596 protected:
597 using ControlFrame::ControlFrame;
598 };
599
600 struct AuthSignatureFrame
601 : public ControlFrame<AuthSignatureFrame,
602 sha256_digest_t> {
603 static const Tag tag = Tag::AUTH_SIGNATURE;
604 using ControlFrame::Encode;
605 using ControlFrame::Decode;
606
607 inline sha256_digest_t &signature() { return get_val<0>(); }
608
609 protected:
610 using ControlFrame::ControlFrame;
611 };
612
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
621 uint64_t, // flags
622 uint64_t> { // client cookie
623 static const Tag tag = Tag::CLIENT_IDENT;
624 using ControlFrame::Encode;
625 using ControlFrame::Decode;
626
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>(); }
635
636 protected:
637 using ControlFrame::ControlFrame;
638 };
639
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
647 uint64_t, // flags
648 uint64_t> { // server cookie
649 static const Tag tag = Tag::SERVER_IDENT;
650 using ControlFrame::Encode;
651 using ControlFrame::Decode;
652
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>(); }
660
661 protected:
662 using ControlFrame::ControlFrame;
663 };
664
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;
676
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>(); }
683
684 protected:
685 using ControlFrame::ControlFrame;
686 };
687
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;
693
694 inline bool &full() { return get_val<0>(); }
695
696 protected:
697 using ControlFrame::ControlFrame;
698 };
699
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;
705
706 inline uint64_t &connect_seq() { return get_val<0>(); }
707
708 protected:
709 using ControlFrame::ControlFrame;
710 };
711
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;
717
718 inline uint64_t &global_seq() { return get_val<0>(); }
719
720 protected:
721 using ControlFrame::ControlFrame;
722 };
723
724 struct WaitFrame : public ControlFrame<WaitFrame> {
725 static const Tag tag = Tag::WAIT;
726 using ControlFrame::Encode;
727 using ControlFrame::Decode;
728
729 protected:
730 using ControlFrame::ControlFrame;
731 };
732
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;
738
739 inline uint64_t &msg_seq() { return get_val<0>(); }
740
741 protected:
742 using ControlFrame::ControlFrame;
743 };
744
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;
751
752 inline uint64_t &features() { return get_val<0>(); }
753
754 protected:
755 using ControlFrame::ControlFrame;
756 };
757
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;
763
764 static KeepAliveFrame Encode() {
765 return KeepAliveFrame::Encode(ceph_clock_now());
766 }
767
768 inline utime_t &timestamp() { return get_val<0>(); }
769
770 protected:
771 using ControlFrame::ControlFrame;
772 };
773
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;
779
780 inline utime_t &timestamp() { return get_val<0>(); }
781
782 protected:
783 using ControlFrame::ControlFrame;
784 };
785
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;
791
792 inline uint64_t &seq() { return get_val<0>(); }
793
794 protected:
795 using ControlFrame::ControlFrame;
796 };
797
798 using segment_bls_t =
799 boost::container::static_vector<bufferlist, MAX_NUM_SEGMENTS>;
800
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,
805 /* four segments */
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;
811
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) {
816 MessageFrame f;
817 f.segments[SegmentIndex::Msg::HEADER].append(
818 reinterpret_cast<const char*>(&msg_header), sizeof(msg_header));
819
820 f.segments[SegmentIndex::Msg::FRONT] = front;
821 f.segments[SegmentIndex::Msg::MIDDLE] = middle;
822 f.segments[SegmentIndex::Msg::DATA] = data;
823
824 return f;
825 }
826
827 static MessageFrame Decode(segment_bls_t& recv_segments) {
828 MessageFrame f;
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]);
833 }
834 return f;
835 }
836
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());
840 }
841
842 ceph::bufferlist &front() {
843 return segments[SegmentIndex::Msg::FRONT];
844 }
845
846 ceph::bufferlist &middle() {
847 return segments[SegmentIndex::Msg::MIDDLE];
848 }
849
850 ceph::bufferlist &data() {
851 return segments[SegmentIndex::Msg::DATA];
852 }
853
854 uint32_t front_len() const {
855 return segments[SegmentIndex::Msg::FRONT].length();
856 }
857
858 uint32_t middle_len() const {
859 return segments[SegmentIndex::Msg::MIDDLE].length();
860 }
861
862 uint32_t data_len() const {
863 return segments[SegmentIndex::Msg::DATA].length();
864 }
865
866 protected:
867 using Frame::Frame;
868 };
869
870 struct CompressionRequestFrame : public ControlFrame<CompressionRequestFrame,
871 bool, // is compress
872 std::vector<uint32_t>> { // preferred methods
873 static const Tag tag = Tag::COMPRESSION_REQUEST;
874 using ControlFrame::Encode;
875 using ControlFrame::Decode;
876
877 inline bool &is_compress() { return get_val<0>(); }
878 inline std::vector<uint32_t> &preferred_methods() { return get_val<1>(); }
879
880 protected:
881 using ControlFrame::ControlFrame;
882 };
883
884 struct CompressionDoneFrame : public ControlFrame<CompressionDoneFrame,
885 bool, // is compress
886 uint32_t> { // method
887 static const Tag tag = Tag::COMPRESSION_DONE;
888 using ControlFrame::Encode;
889 using ControlFrame::Decode;
890
891 inline bool &is_compress() { return get_val<0>(); }
892 inline uint32_t &method() { return get_val<1>(); }
893
894 protected:
895 using ControlFrame::ControlFrame;
896 };
897
898 } // namespace ceph::msgr::v2
899
900 #endif // _MSG_ASYNC_FRAMES_V2_