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