]> git.proxmox.com Git - ceph.git/blame - ceph/src/msg/async/frames_v2.h
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / msg / async / frames_v2.h
CommitLineData
11fdf7f2
TL
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
16namespace ceph::msgr::v2 {
17
18// We require these features from any peer, period, in order to encode
19// a entity_addrvec_t.
20const 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.
31const uint64_t msgr2_frame_assumed =
32 msgr2_required |
33 CEPH_FEATUREMASK_SERVER_NAUTILUS;
34
35enum 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
58struct 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 __le16 PAGE_SIZE_ALIGNMENT{4096};
62
63 static constexpr __le16 DEFAULT_ALIGNMENT = sizeof(void *);
64
eafe8130
TL
65 ceph_le32 length;
66 ceph_le16 alignment;
11fdf7f2
TL
67} __attribute__((packed));
68
69struct 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
82static constexpr uint8_t CRYPTO_BLOCK_SIZE { 16 };
83
84static 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.
91struct 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 std::array<segment_t, MAX_NUM_SEGMENTS> segments;
102 __u8 _reserved[2];
103
104 // CRC32 for this single preamble block.
eafe8130 105 ceph_le32 crc;
11fdf7f2
TL
106} __attribute__((packed));
107static_assert(sizeof(preamble_block_t) % CRYPTO_BLOCK_SIZE == 0);
108static_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.
129struct epilogue_plain_block_t {
130 __u8 late_flags;
eafe8130 131 std::array<ceph_le32, MAX_NUM_SEGMENTS> crc_values;
11fdf7f2
TL
132} __attribute__((packed));
133static_assert(std::is_standard_layout<epilogue_plain_block_t>::value);
134
135struct 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));
141static_assert(sizeof(epilogue_secure_block_t) % CRYPTO_BLOCK_SIZE == 0);
142static_assert(std::is_standard_layout<epilogue_secure_block_t>::value);
143
144
145static constexpr uint32_t FRAME_PREAMBLE_SIZE = sizeof(preamble_block_t);
146static constexpr uint32_t FRAME_PLAIN_EPILOGUE_SIZE =
147 sizeof(epilogue_plain_block_t);
148static 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
153static uint32_t segment_onwire_size(const uint32_t logical_size)
154{
155 return p2roundup<uint32_t>(logical_size, CRYPTO_BLOCK_SIZE);
156}
157
158static 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 bl;
165}
166
167template <class T, uint16_t... SegmentAlignmentVs>
168struct Frame {
169 static constexpr size_t SegmentsNumV = sizeof...(SegmentAlignmentVs);
170 static_assert(SegmentsNumV > 0 && SegmentsNumV <= MAX_NUM_SEGMENTS);
171protected:
172 std::array<ceph::bufferlist, SegmentsNumV> segments;
173
174private:
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(
181 const std::array<segment_t, MAX_NUM_SEGMENTS>& segments)
182 {
183 for (__u8 num = SegmentsNumV; num > 0; num--) {
184 if (segments[num-1].length) {
185 return num;
186 }
187 }
188 // frame always has at least one segment.
189 return 1;
190 }
191
192 // craft the main preamble. It's always present regardless of the number
193 // of segments message is composed from.
194 void fill_preamble() {
195 ceph_assert(std::size(segments) <= MAX_NUM_SEGMENTS);
196
197 preamble_block_t main_preamble;
92f5a8d4 198 // FIPS zeroization audit 20191115: this memset is not security related.
11fdf7f2
TL
199 ::memset(&main_preamble, 0, sizeof(main_preamble));
200
201 main_preamble.tag = static_cast<__u8>(T::tag);
202 ceph_assert(main_preamble.tag != 0);
203
204 // implementation detail: the first bufferlist of Frame::segments carries
205 // space for preamble. This glueing isn't a part of the onwire format but
206 // just our private detail.
207 main_preamble.segments.front().length =
208 segments.front().length() - FRAME_PREAMBLE_SIZE;
209 main_preamble.segments.front().alignment = alignments.front();
210
211 // there is no business in issuing frame without at least one segment
212 // filled.
213 if constexpr(SegmentsNumV > 1) {
214 for (__u8 idx = 1; idx < SegmentsNumV; idx++) {
215 main_preamble.segments[idx].length = segments[idx].length();
216 main_preamble.segments[idx].alignment = alignments[idx];
217 }
218 }
219 // calculate the number of non-empty segments.
220 // TODO: reorder segments to get DATA first
221 main_preamble.num_segments = calc_num_segments(main_preamble.segments);
222
223 main_preamble.crc =
224 ceph_crc32c(0, reinterpret_cast<unsigned char *>(&main_preamble),
225 sizeof(main_preamble) - sizeof(main_preamble.crc));
226
227 preamble_filler.copy_in(sizeof(main_preamble),
228 reinterpret_cast<const char *>(&main_preamble));
229 }
230
231 template <size_t... Is>
232 void reset_tx_handler(
233 ceph::crypto::onwire::rxtx_t &session_stream_handlers,
234 std::index_sequence<Is...>)
235 {
236 session_stream_handlers.tx->reset_tx_handler({ segments[Is].length()... });
237 }
238
239public:
240 ceph::bufferlist get_buffer(
241 ceph::crypto::onwire::rxtx_t &session_stream_handlers)
242 {
243 fill_preamble();
244 if (session_stream_handlers.tx) {
245 // we're padding segments to biggest cipher's block size. Although
246 // AES-GCM can live without that as it's a stream cipher, we don't
247 // to be fixed to stream ciphers only.
248 for (auto& segment : segments) {
249 segment = segment_onwire_bufferlist(std::move(segment));
250 }
251
252 // let's cipher allocate one huge buffer for entire ciphertext.
253 reset_tx_handler(
254 session_stream_handlers, std::make_index_sequence<SegmentsNumV>());
255
256 for (auto& segment : segments) {
257 if (segment.length()) {
258 session_stream_handlers.tx->authenticated_encrypt_update(
259 std::move(segment));
260 }
261 }
262
263 // in secure mode we craft only the late_flags. Signature (for AES-GCM
264 // called auth tag) will be added by the cipher.
265 {
266 epilogue_secure_block_t epilogue;
92f5a8d4
TL
267 // FIPS zeroization audit 20191115: this memset is not security
268 // related.
11fdf7f2
TL
269 ::memset(&epilogue, 0, sizeof(epilogue));
270 ceph::bufferlist epilogue_bl;
271 epilogue_bl.append(reinterpret_cast<const char*>(&epilogue),
272 sizeof(epilogue));
273 session_stream_handlers.tx->authenticated_encrypt_update(epilogue_bl);
274 }
275 return session_stream_handlers.tx->authenticated_encrypt_final();
276 } else {
277 // plain mode
278 epilogue_plain_block_t epilogue;
92f5a8d4 279 // FIPS zeroization audit 20191115: this memset is not security related.
11fdf7f2
TL
280 ::memset(&epilogue, 0, sizeof(epilogue));
281
282 ceph::bufferlist::const_iterator hdriter(&segments.front(),
283 FRAME_PREAMBLE_SIZE);
284 epilogue.crc_values[SegmentIndex::Control::PAYLOAD] =
285 hdriter.crc32c(hdriter.get_remaining(), -1);
286 if constexpr(SegmentsNumV > 1) {
287 for (__u8 idx = 1; idx < SegmentsNumV; idx++) {
288 epilogue.crc_values[idx] = segments[idx].crc32c(-1);
289 }
290 }
291
292 ceph::bufferlist ret;
293 for (auto& segment : segments) {
294 ret.claim_append(segment);
295 }
296 ret.append(reinterpret_cast<const char*>(&epilogue), sizeof(epilogue));
297 return ret;
298 }
299 }
300
301 Frame()
302 : preamble_filler(segments.front().append_hole(FRAME_PREAMBLE_SIZE)) {
303 }
304
305public:
306};
307
308
309// ControlFrames are used to manage transceiver state (like connections) and
310// orchestrate transfers of MessageFrames. They use only single segment with
311// marshalling facilities -- derived classes specify frame structure through
312// Args pack while ControlFrame provides common encode/decode machinery.
313template <class C, typename... Args>
314class ControlFrame : public Frame<C, segment_t::DEFAULT_ALIGNMENT /* single segment */> {
315protected:
316 ceph::bufferlist &get_payload_segment() {
317 return this->segments[SegmentIndex::Control::PAYLOAD];
318 }
319
320 // this tuple is only used when decoding values from a payload segment
321 std::tuple<Args...> _values;
322
323 // FIXME: for now, we assume specific features for the purpoess of encoding
324 // the frames themselves (*not* messages in message frames!).
325 uint64_t features = msgr2_frame_assumed;
326
327 template <typename T>
328 inline void _encode_payload_each(T &t) {
329 if constexpr (std::is_same<T, std::vector<uint32_t> const>()) {
330 encode((uint32_t)t.size(), this->get_payload_segment(), features);
331 for (const auto &elem : t) {
332 encode(elem, this->get_payload_segment(), features);
333 }
334 } else {
335 encode(t, this->get_payload_segment(), features);
336 }
337 }
338
339 template <typename T>
340 inline void _decode_payload_each(T &t, bufferlist::const_iterator &ti) const {
341 if constexpr (std::is_same<T, std::vector<uint32_t>>()) {
342 uint32_t size;
343 decode(size, ti);
344 t.resize(size);
345 for (uint32_t i = 0; i < size; ++i) {
346 decode(t[i], ti);
347 }
348 } else {
349 decode(t, ti);
350 }
351 }
352
353 template <std::size_t... Is>
354 inline void _decode_payload(bufferlist::const_iterator &ti,
355 std::index_sequence<Is...>) const {
356 (_decode_payload_each((Args &)std::get<Is>(_values), ti), ...);
357 }
358
359 template <std::size_t N>
360 inline decltype(auto) get_val() {
361 return std::get<N>(_values);
362 }
363
364 ControlFrame()
365 : Frame<C, segment_t::DEFAULT_ALIGNMENT /* single segment */>() {
366 }
367
368 void _encode(const Args &... args) {
369 (_encode_payload_each(args), ...);
370 }
371
372 void _decode(const ceph::bufferlist &bl) {
373 auto ti = bl.cbegin();
374 _decode_payload(ti, std::index_sequence_for<Args...>());
375 }
376
377public:
378 static C Encode(const Args &... args) {
379 C c;
380 c._encode(args...);
381 return c;
382 }
383
384 static C Decode(const ceph::bufferlist &payload) {
385 C c;
386 c._decode(payload);
387 return c;
388 }
389};
390
391struct HelloFrame : public ControlFrame<HelloFrame,
392 uint8_t, // entity type
393 entity_addr_t> { // peer address
394 static const Tag tag = Tag::HELLO;
395 using ControlFrame::Encode;
396 using ControlFrame::Decode;
397
398 inline uint8_t &entity_type() { return get_val<0>(); }
399 inline entity_addr_t &peer_addr() { return get_val<1>(); }
400
401protected:
402 using ControlFrame::ControlFrame;
403};
404
405struct AuthRequestFrame : public ControlFrame<AuthRequestFrame,
406 uint32_t, // auth method
407 vector<uint32_t>, // preferred modes
408 bufferlist> { // auth payload
409 static const Tag tag = Tag::AUTH_REQUEST;
410 using ControlFrame::Encode;
411 using ControlFrame::Decode;
412
413 inline uint32_t &method() { return get_val<0>(); }
414 inline vector<uint32_t> &preferred_modes() { return get_val<1>(); }
415 inline bufferlist &auth_payload() { return get_val<2>(); }
416
417protected:
418 using ControlFrame::ControlFrame;
419};
420
421struct AuthBadMethodFrame : public ControlFrame<AuthBadMethodFrame,
422 uint32_t, // method
423 int32_t, // result
424 std::vector<uint32_t>, // allowed methods
425 std::vector<uint32_t>> { // allowed modes
426 static const Tag tag = Tag::AUTH_BAD_METHOD;
427 using ControlFrame::Encode;
428 using ControlFrame::Decode;
429
430 inline uint32_t &method() { return get_val<0>(); }
431 inline int32_t &result() { return get_val<1>(); }
432 inline std::vector<uint32_t> &allowed_methods() { return get_val<2>(); }
433 inline std::vector<uint32_t> &allowed_modes() { return get_val<3>(); }
434
435protected:
436 using ControlFrame::ControlFrame;
437};
438
439struct AuthReplyMoreFrame : public ControlFrame<AuthReplyMoreFrame,
440 bufferlist> { // auth payload
441 static const Tag tag = Tag::AUTH_REPLY_MORE;
442 using ControlFrame::Encode;
443 using ControlFrame::Decode;
444
445 inline bufferlist &auth_payload() { return get_val<0>(); }
446
447protected:
448 using ControlFrame::ControlFrame;
449};
450
451struct AuthRequestMoreFrame : public ControlFrame<AuthRequestMoreFrame,
452 bufferlist> { // auth payload
453 static const Tag tag = Tag::AUTH_REQUEST_MORE;
454 using ControlFrame::Encode;
455 using ControlFrame::Decode;
456
457 inline bufferlist &auth_payload() { return get_val<0>(); }
458
459protected:
460 using ControlFrame::ControlFrame;
461};
462
463struct AuthDoneFrame : public ControlFrame<AuthDoneFrame,
464 uint64_t, // global id
465 uint32_t, // connection mode
466 bufferlist> { // auth method payload
467 static const Tag tag = Tag::AUTH_DONE;
468 using ControlFrame::Encode;
469 using ControlFrame::Decode;
470
471 inline uint64_t &global_id() { return get_val<0>(); }
472 inline uint32_t &con_mode() { return get_val<1>(); }
473 inline bufferlist &auth_payload() { return get_val<2>(); }
474
475protected:
476 using ControlFrame::ControlFrame;
477};
478
479struct AuthSignatureFrame
480 : public ControlFrame<AuthSignatureFrame,
481 sha256_digest_t> {
482 static const Tag tag = Tag::AUTH_SIGNATURE;
483 using ControlFrame::Encode;
484 using ControlFrame::Decode;
485
486 inline sha256_digest_t &signature() { return get_val<0>(); }
487
488protected:
489 using ControlFrame::ControlFrame;
490};
491
492struct ClientIdentFrame
493 : public ControlFrame<ClientIdentFrame,
494 entity_addrvec_t, // my addresses
495 entity_addr_t, // target address
496 int64_t, // global_id
497 uint64_t, // global seq
498 uint64_t, // supported features
499 uint64_t, // required features
500 uint64_t, // flags
501 uint64_t> { // client cookie
502 static const Tag tag = Tag::CLIENT_IDENT;
503 using ControlFrame::Encode;
504 using ControlFrame::Decode;
505
506 inline entity_addrvec_t &addrs() { return get_val<0>(); }
507 inline entity_addr_t &target_addr() { return get_val<1>(); }
508 inline int64_t &gid() { return get_val<2>(); }
509 inline uint64_t &global_seq() { return get_val<3>(); }
510 inline uint64_t &supported_features() { return get_val<4>(); }
511 inline uint64_t &required_features() { return get_val<5>(); }
512 inline uint64_t &flags() { return get_val<6>(); }
513 inline uint64_t &cookie() { return get_val<7>(); }
514
515protected:
516 using ControlFrame::ControlFrame;
517};
518
519struct ServerIdentFrame
520 : public ControlFrame<ServerIdentFrame,
521 entity_addrvec_t, // my addresses
522 int64_t, // global_id
523 uint64_t, // global seq
524 uint64_t, // supported features
525 uint64_t, // required features
526 uint64_t, // flags
527 uint64_t> { // server cookie
528 static const Tag tag = Tag::SERVER_IDENT;
529 using ControlFrame::Encode;
530 using ControlFrame::Decode;
531
532 inline entity_addrvec_t &addrs() { return get_val<0>(); }
533 inline int64_t &gid() { return get_val<1>(); }
534 inline uint64_t &global_seq() { return get_val<2>(); }
535 inline uint64_t &supported_features() { return get_val<3>(); }
536 inline uint64_t &required_features() { return get_val<4>(); }
537 inline uint64_t &flags() { return get_val<5>(); }
538 inline uint64_t &cookie() { return get_val<6>(); }
539
540protected:
541 using ControlFrame::ControlFrame;
542};
543
544struct ReconnectFrame
545 : public ControlFrame<ReconnectFrame,
546 entity_addrvec_t, // my addresses
547 uint64_t, // client cookie
548 uint64_t, // server cookie
549 uint64_t, // global sequence
550 uint64_t, // connect sequence
551 uint64_t> { // message sequence
552 static const Tag tag = Tag::SESSION_RECONNECT;
553 using ControlFrame::Encode;
554 using ControlFrame::Decode;
555
556 inline entity_addrvec_t &addrs() { return get_val<0>(); }
557 inline uint64_t &client_cookie() { return get_val<1>(); }
558 inline uint64_t &server_cookie() { return get_val<2>(); }
559 inline uint64_t &global_seq() { return get_val<3>(); }
560 inline uint64_t &connect_seq() { return get_val<4>(); }
561 inline uint64_t &msg_seq() { return get_val<5>(); }
562
563protected:
564 using ControlFrame::ControlFrame;
565};
566
567struct ResetFrame : public ControlFrame<ResetFrame,
568 bool> { // full reset
569 static const Tag tag = Tag::SESSION_RESET;
570 using ControlFrame::Encode;
571 using ControlFrame::Decode;
572
573 inline bool &full() { return get_val<0>(); }
574
575protected:
576 using ControlFrame::ControlFrame;
577};
578
579struct RetryFrame : public ControlFrame<RetryFrame,
580 uint64_t> { // connection seq
581 static const Tag tag = Tag::SESSION_RETRY;
582 using ControlFrame::Encode;
583 using ControlFrame::Decode;
584
585 inline uint64_t &connect_seq() { return get_val<0>(); }
586
587protected:
588 using ControlFrame::ControlFrame;
589};
590
591struct RetryGlobalFrame : public ControlFrame<RetryGlobalFrame,
592 uint64_t> { // global seq
593 static const Tag tag = Tag::SESSION_RETRY_GLOBAL;
594 using ControlFrame::Encode;
595 using ControlFrame::Decode;
596
597 inline uint64_t &global_seq() { return get_val<0>(); }
598
599protected:
600 using ControlFrame::ControlFrame;
601};
602
603struct WaitFrame : public ControlFrame<WaitFrame> {
604 static const Tag tag = Tag::WAIT;
605 using ControlFrame::Encode;
606 using ControlFrame::Decode;
607
608protected:
609 using ControlFrame::ControlFrame;
610};
611
612struct ReconnectOkFrame : public ControlFrame<ReconnectOkFrame,
613 uint64_t> { // message seq
614 static const Tag tag = Tag::SESSION_RECONNECT_OK;
615 using ControlFrame::Encode;
616 using ControlFrame::Decode;
617
618 inline uint64_t &msg_seq() { return get_val<0>(); }
619
620protected:
621 using ControlFrame::ControlFrame;
622};
623
624struct IdentMissingFeaturesFrame
625 : public ControlFrame<IdentMissingFeaturesFrame,
626 uint64_t> { // missing features mask
627 static const Tag tag = Tag::IDENT_MISSING_FEATURES;
628 using ControlFrame::Encode;
629 using ControlFrame::Decode;
630
631 inline uint64_t &features() { return get_val<0>(); }
632
633protected:
634 using ControlFrame::ControlFrame;
635};
636
637struct KeepAliveFrame : public ControlFrame<KeepAliveFrame,
638 utime_t> { // timestamp
639 static const Tag tag = Tag::KEEPALIVE2;
640 using ControlFrame::Encode;
641 using ControlFrame::Decode;
642
643 static KeepAliveFrame Encode() {
644 return KeepAliveFrame::Encode(ceph_clock_now());
645 }
646
647 inline utime_t &timestamp() { return get_val<0>(); }
648
649protected:
650 using ControlFrame::ControlFrame;
651};
652
653struct KeepAliveFrameAck : public ControlFrame<KeepAliveFrameAck,
654 utime_t> { // ack timestamp
655 static const Tag tag = Tag::KEEPALIVE2_ACK;
656 using ControlFrame::Encode;
657 using ControlFrame::Decode;
658
659 inline utime_t &timestamp() { return get_val<0>(); }
660
661protected:
662 using ControlFrame::ControlFrame;
663};
664
665struct AckFrame : public ControlFrame<AckFrame,
666 uint64_t> { // message sequence
667 static const Tag tag = Tag::ACK;
668 using ControlFrame::Encode;
669 using ControlFrame::Decode;
670
671 inline uint64_t &seq() { return get_val<0>(); }
672
673protected:
674 using ControlFrame::ControlFrame;
675};
676
677// This class is used for encoding/decoding header of the message frame.
678// Body is processed almost independently with the sole junction point
679// being the `extra_payload_len` passed to get_buffer().
680struct MessageFrame : public Frame<MessageFrame,
681 /* four segments */
682 segment_t::DEFAULT_ALIGNMENT,
683 segment_t::DEFAULT_ALIGNMENT,
684 segment_t::DEFAULT_ALIGNMENT,
685 segment_t::PAGE_SIZE_ALIGNMENT> {
686 struct {
687 uint32_t front;
688 uint32_t middle;
689 uint32_t data;
690 } len;
691
692 static const Tag tag = Tag::MESSAGE;
693
694 static MessageFrame Encode(const ceph_msg_header2 &msg_header,
695 const ceph::bufferlist &front,
696 const ceph::bufferlist &middle,
697 const ceph::bufferlist &data) {
698 MessageFrame f;
699 f.segments[SegmentIndex::Msg::HEADER].append(
700 reinterpret_cast<const char*>(&msg_header), sizeof(msg_header));
701
702 f.segments[SegmentIndex::Msg::FRONT] = front;
703 f.segments[SegmentIndex::Msg::MIDDLE] = middle;
704 f.segments[SegmentIndex::Msg::DATA] = data;
705
706 return f;
707 }
708
709 using rx_segments_t =
710 boost::container::static_vector<ceph::bufferlist,
711 ceph::msgr::v2::MAX_NUM_SEGMENTS>;
712 static MessageFrame Decode(rx_segments_t &&recv_segments) {
713 MessageFrame f;
714 // transfer segments' bufferlists. If a MessageFrame contains less
715 // SegmentsNumV segments, the missing ones will be seen as zeroed.
716 for (__u8 idx = 0; idx < std::size(recv_segments); idx++) {
717 f.segments[idx] = std::move(recv_segments[idx]);
718 }
719 return f;
720 }
721
722 inline const ceph_msg_header2 &header() {
723 auto& hdrbl = segments[SegmentIndex::Msg::HEADER];
724 return reinterpret_cast<const ceph_msg_header2&>(*hdrbl.c_str());
725 }
726
727 ceph::bufferlist &front() {
728 return segments[SegmentIndex::Msg::FRONT];
729 }
730
731 ceph::bufferlist &middle() {
732 return segments[SegmentIndex::Msg::MIDDLE];
733 }
734
735 ceph::bufferlist &data() {
736 return segments[SegmentIndex::Msg::DATA];
737 }
738
739 uint32_t front_len() const {
740 return segments[SegmentIndex::Msg::FRONT].length();
741 }
742
743 uint32_t middle_len() const {
744 return segments[SegmentIndex::Msg::MIDDLE].length();
745 }
746
747 uint32_t data_len() const {
748 return segments[SegmentIndex::Msg::DATA].length();
749 }
750
751protected:
752 using Frame::Frame;
753};
754
755} // namespace ceph::msgr::v2
756
757#endif // _MSG_ASYNC_FRAMES_V2_