]> git.proxmox.com Git - ceph.git/blob - ceph/src/msg/async/frames_v2.h
import 15.2.0 Octopus source
[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 <array>
8 #include <utility>
9
10 /**
11 * Protocol V2 Frame Structures
12 *
13 * Documentation in: doc/dev/msgr2.rst
14 **/
15
16 namespace ceph::msgr::v2 {
17
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;
21
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 =
32 msgr2_required |
33 CEPH_FEATUREMASK_SERVER_NAUTILUS;
34
35 enum class Tag : __u8 {
36 HELLO = 1,
37 AUTH_REQUEST,
38 AUTH_BAD_METHOD,
39 AUTH_REPLY_MORE,
40 AUTH_REQUEST_MORE,
41 AUTH_DONE,
42 AUTH_SIGNATURE,
43 CLIENT_IDENT,
44 SERVER_IDENT,
45 IDENT_MISSING_FEATURES,
46 SESSION_RECONNECT,
47 SESSION_RESET,
48 SESSION_RETRY,
49 SESSION_RETRY_GLOBAL,
50 SESSION_RECONNECT_OK,
51 WAIT,
52 MESSAGE,
53 KEEPALIVE2,
54 KEEPALIVE2_ACK,
55 ACK
56 };
57
58 struct segment_t {
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;
62
63 static constexpr __u16 DEFAULT_ALIGNMENT = sizeof(void *);
64
65 ceph_le32 length;
66 ceph_le16 alignment;
67 } __attribute__((packed));
68
69 struct SegmentIndex {
70 struct Msg {
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;
75 };
76
77 struct Control {
78 static constexpr std::size_t PAYLOAD = 0;
79 };
80 };
81
82 static constexpr uint8_t CRYPTO_BLOCK_SIZE { 16 };
83
84 static constexpr std::size_t MAX_NUM_SEGMENTS = 4;
85
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.
89 //
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.
94 __u8 tag;
95
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.
99 __u8 num_segments;
100
101 segment_t segments[MAX_NUM_SEGMENTS];
102 __u8 _reserved[2];
103
104 // CRC32 for this single preamble block.
105 ceph_le32 crc;
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);
109
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.
119 //
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).
125 //
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 {
130 __u8 late_flags;
131 ceph_le32 crc_values[MAX_NUM_SEGMENTS];
132 } __attribute__((packed));
133 static_assert(std::is_standard_layout<epilogue_plain_block_t>::value);
134
135 struct epilogue_secure_block_t {
136 __u8 late_flags;
137 __u8 padding[CRYPTO_BLOCK_SIZE - sizeof(late_flags)];
138
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);
143
144
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);
150
151 #define FRAME_FLAGS_LATEABRT (1<<0) /* frame was aborted after txing data */
152
153 static uint32_t segment_onwire_size(const uint32_t logical_size)
154 {
155 return p2roundup<uint32_t>(logical_size, CRYPTO_BLOCK_SIZE);
156 }
157
158 static inline ceph::bufferlist segment_onwire_bufferlist(ceph::bufferlist&& bl)
159 {
160 const auto padding_size = segment_onwire_size(bl.length()) - bl.length();
161 if (padding_size) {
162 bl.append_zero(padding_size);
163 }
164 return std::move(bl);
165 }
166
167 template <class T, uint16_t... SegmentAlignmentVs>
168 struct Frame {
169 static constexpr size_t SegmentsNumV = sizeof...(SegmentAlignmentVs);
170 static_assert(SegmentsNumV > 0 && SegmentsNumV <= MAX_NUM_SEGMENTS);
171 protected:
172 std::array<ceph::bufferlist, SegmentsNumV> segments;
173
174 private:
175 static constexpr std::array<uint16_t, SegmentsNumV> alignments {
176 SegmentAlignmentVs...
177 };
178 ceph::bufferlist::contiguous_filler preamble_filler;
179
180 __u8 calc_num_segments(const segment_t segments[])
181 {
182 for (__u8 num = SegmentsNumV; num > 0; num--) {
183 if (segments[num-1].length) {
184 return num;
185 }
186 }
187 // frame always has at least one segment.
188 return 1;
189 }
190
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);
195
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));
199
200 main_preamble.tag = static_cast<__u8>(T::tag);
201 ceph_assert(main_preamble.tag != 0);
202
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];
209
210 // there is no business in issuing frame without at least one segment
211 // filled.
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];
216 }
217 }
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);
221
222 main_preamble.crc =
223 ceph_crc32c(0, reinterpret_cast<unsigned char *>(&main_preamble),
224 sizeof(main_preamble) - sizeof(main_preamble.crc));
225
226 preamble_filler.copy_in(sizeof(main_preamble),
227 reinterpret_cast<const char *>(&main_preamble));
228 }
229
230 template <size_t... Is>
231 void reset_tx_handler(
232 ceph::crypto::onwire::rxtx_t &session_stream_handlers,
233 std::index_sequence<Is...>)
234 {
235 session_stream_handlers.tx->reset_tx_handler({ segments[Is].length()... });
236 }
237
238 public:
239 ceph::bufferlist get_buffer(
240 ceph::crypto::onwire::rxtx_t &session_stream_handlers)
241 {
242 fill_preamble();
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));
249 }
250
251 // let's cipher allocate one huge buffer for entire ciphertext.
252 reset_tx_handler(
253 session_stream_handlers, std::make_index_sequence<SegmentsNumV>());
254
255 for (auto& segment : segments) {
256 if (segment.length()) {
257 session_stream_handlers.tx->authenticated_encrypt_update(
258 std::move(segment));
259 }
260 }
261
262 // in secure mode we craft only the late_flags. Signature (for AES-GCM
263 // called auth tag) will be added by the cipher.
264 {
265 epilogue_secure_block_t epilogue;
266 // FIPS zeroization audit 20191115: this memset is not security
267 // related.
268 ::memset(&epilogue, 0, sizeof(epilogue));
269 ceph::bufferlist epilogue_bl;
270 epilogue_bl.append(reinterpret_cast<const char*>(&epilogue),
271 sizeof(epilogue));
272 session_stream_handlers.tx->authenticated_encrypt_update(epilogue_bl);
273 }
274 return session_stream_handlers.tx->authenticated_encrypt_final();
275 } else {
276 // plain mode
277 epilogue_plain_block_t epilogue;
278 // FIPS zeroization audit 20191115: this memset is not security related.
279 ::memset(&epilogue, 0, sizeof(epilogue));
280
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);
288 }
289 }
290
291 ceph::bufferlist ret;
292 for (auto& segment : segments) {
293 ret.claim_append(segment);
294 }
295 ret.append(reinterpret_cast<const char*>(&epilogue), sizeof(epilogue));
296 return ret;
297 }
298 }
299
300 Frame()
301 : preamble_filler(segments.front().append_hole(FRAME_PREAMBLE_SIZE)) {
302 }
303
304 public:
305 };
306
307
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 */> {
314 protected:
315 ceph::bufferlist &get_payload_segment() {
316 return this->segments[SegmentIndex::Control::PAYLOAD];
317 }
318
319 // this tuple is only used when decoding values from a payload segment
320 std::tuple<Args...> _values;
321
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;
325
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);
332 }
333 } else {
334 encode(t, this->get_payload_segment(), features);
335 }
336 }
337
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>>()) {
341 uint32_t size;
342 decode(size, ti);
343 t.resize(size);
344 for (uint32_t i = 0; i < size; ++i) {
345 decode(t[i], ti);
346 }
347 } else {
348 decode(t, ti);
349 }
350 }
351
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), ...);
356 }
357
358 template <std::size_t N>
359 inline decltype(auto) get_val() {
360 return std::get<N>(_values);
361 }
362
363 ControlFrame()
364 : Frame<C, segment_t::DEFAULT_ALIGNMENT /* single segment */>() {
365 }
366
367 void _encode(const Args &... args) {
368 (_encode_payload_each(args), ...);
369 }
370
371 void _decode(const ceph::bufferlist &bl) {
372 auto ti = bl.cbegin();
373 _decode_payload(ti, std::index_sequence_for<Args...>());
374 }
375
376 public:
377 static C Encode(const Args &... args) {
378 C c;
379 c._encode(args...);
380 return c;
381 }
382
383 static C Decode(const ceph::bufferlist &payload) {
384 C c;
385 c._decode(payload);
386 return c;
387 }
388 };
389
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;
396
397 inline uint8_t &entity_type() { return get_val<0>(); }
398 inline entity_addr_t &peer_addr() { return get_val<1>(); }
399
400 protected:
401 using ControlFrame::ControlFrame;
402 };
403
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;
411
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>(); }
415
416 protected:
417 using ControlFrame::ControlFrame;
418 };
419
420 struct AuthBadMethodFrame : public ControlFrame<AuthBadMethodFrame,
421 uint32_t, // method
422 int32_t, // result
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;
428
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>(); }
433
434 protected:
435 using ControlFrame::ControlFrame;
436 };
437
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;
443
444 inline bufferlist &auth_payload() { return get_val<0>(); }
445
446 protected:
447 using ControlFrame::ControlFrame;
448 };
449
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;
455
456 inline bufferlist &auth_payload() { return get_val<0>(); }
457
458 protected:
459 using ControlFrame::ControlFrame;
460 };
461
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;
469
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>(); }
473
474 protected:
475 using ControlFrame::ControlFrame;
476 };
477
478 struct AuthSignatureFrame
479 : public ControlFrame<AuthSignatureFrame,
480 sha256_digest_t> {
481 static const Tag tag = Tag::AUTH_SIGNATURE;
482 using ControlFrame::Encode;
483 using ControlFrame::Decode;
484
485 inline sha256_digest_t &signature() { return get_val<0>(); }
486
487 protected:
488 using ControlFrame::ControlFrame;
489 };
490
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
499 uint64_t, // flags
500 uint64_t> { // client cookie
501 static const Tag tag = Tag::CLIENT_IDENT;
502 using ControlFrame::Encode;
503 using ControlFrame::Decode;
504
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>(); }
513
514 protected:
515 using ControlFrame::ControlFrame;
516 };
517
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
525 uint64_t, // flags
526 uint64_t> { // server cookie
527 static const Tag tag = Tag::SERVER_IDENT;
528 using ControlFrame::Encode;
529 using ControlFrame::Decode;
530
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>(); }
538
539 protected:
540 using ControlFrame::ControlFrame;
541 };
542
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;
554
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>(); }
561
562 protected:
563 using ControlFrame::ControlFrame;
564 };
565
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;
571
572 inline bool &full() { return get_val<0>(); }
573
574 protected:
575 using ControlFrame::ControlFrame;
576 };
577
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;
583
584 inline uint64_t &connect_seq() { return get_val<0>(); }
585
586 protected:
587 using ControlFrame::ControlFrame;
588 };
589
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;
595
596 inline uint64_t &global_seq() { return get_val<0>(); }
597
598 protected:
599 using ControlFrame::ControlFrame;
600 };
601
602 struct WaitFrame : public ControlFrame<WaitFrame> {
603 static const Tag tag = Tag::WAIT;
604 using ControlFrame::Encode;
605 using ControlFrame::Decode;
606
607 protected:
608 using ControlFrame::ControlFrame;
609 };
610
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;
616
617 inline uint64_t &msg_seq() { return get_val<0>(); }
618
619 protected:
620 using ControlFrame::ControlFrame;
621 };
622
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;
629
630 inline uint64_t &features() { return get_val<0>(); }
631
632 protected:
633 using ControlFrame::ControlFrame;
634 };
635
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;
641
642 static KeepAliveFrame Encode() {
643 return KeepAliveFrame::Encode(ceph_clock_now());
644 }
645
646 inline utime_t &timestamp() { return get_val<0>(); }
647
648 protected:
649 using ControlFrame::ControlFrame;
650 };
651
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;
657
658 inline utime_t &timestamp() { return get_val<0>(); }
659
660 protected:
661 using ControlFrame::ControlFrame;
662 };
663
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;
669
670 inline uint64_t &seq() { return get_val<0>(); }
671
672 protected:
673 using ControlFrame::ControlFrame;
674 };
675
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,
680 /* four segments */
681 segment_t::DEFAULT_ALIGNMENT,
682 segment_t::DEFAULT_ALIGNMENT,
683 segment_t::DEFAULT_ALIGNMENT,
684 segment_t::PAGE_SIZE_ALIGNMENT> {
685 struct {
686 uint32_t front;
687 uint32_t middle;
688 uint32_t data;
689 } len;
690
691 static const Tag tag = Tag::MESSAGE;
692
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) {
697 MessageFrame f;
698 f.segments[SegmentIndex::Msg::HEADER].append(
699 reinterpret_cast<const char*>(&msg_header), sizeof(msg_header));
700
701 f.segments[SegmentIndex::Msg::FRONT] = front;
702 f.segments[SegmentIndex::Msg::MIDDLE] = middle;
703 f.segments[SegmentIndex::Msg::DATA] = data;
704
705 return f;
706 }
707
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) {
712 MessageFrame f;
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]);
717 }
718 return f;
719 }
720
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());
724 }
725
726 ceph::bufferlist &front() {
727 return segments[SegmentIndex::Msg::FRONT];
728 }
729
730 ceph::bufferlist &middle() {
731 return segments[SegmentIndex::Msg::MIDDLE];
732 }
733
734 ceph::bufferlist &data() {
735 return segments[SegmentIndex::Msg::DATA];
736 }
737
738 uint32_t front_len() const {
739 return segments[SegmentIndex::Msg::FRONT].length();
740 }
741
742 uint32_t middle_len() const {
743 return segments[SegmentIndex::Msg::MIDDLE].length();
744 }
745
746 uint32_t data_len() const {
747 return segments[SegmentIndex::Msg::DATA].length();
748 }
749
750 protected:
751 using Frame::Frame;
752 };
753
754 } // namespace ceph::msgr::v2
755
756 #endif // _MSG_ASYNC_FRAMES_V2_