這是由SimpleMessenger實現(xiàn)的Ceph on-wire protocol的修訂版。它解決了性能和安全問題。
目標
修訂版protocol有幾個與原始protocol相關(guān)的目標:
- 靈活的handshaking。原始協(xié)議沒有足夠靈活的協(xié)議協(xié)商,2允許不需要的功能。
- 加密。在線路中進行加密。
- 性能。我們希望提供協(xié)議功能(例如,填充),以便在可能的情況下將計算和內(nèi)存副本保留在快速路徑之外。
- 簽字。我們將允許對流量進行簽名(但不一定是加密的)。這可能不會在初始版本中實現(xiàn)。
定義
- client(C):發(fā)起(TCP)連接的一方
- server(S):接受(TCP)連接的一方
- connection:兩個進程之間的(TCP)連接的實例。
- entity:一個ceph實體,例如'osd.0'。每個實體憑借“nonce”字段具有一個或多個唯一的entity_addr_t,該字段通常是pid或隨機值。
- session:兩個實體之間的有狀態(tài)會話,其中消息交換是有序的,無損的。如果存在中斷(TCP連接斷開),則會話可能跨越多個連接。
- frame:對等體之間發(fā)送的離散消息。每個幀由標記(類型代碼),有效負載和(如果啟用了簽名或加密)一些其他字段組成。請參閱下面的結(jié)構(gòu)。
- tag:與幀關(guān)聯(lián)的類型代碼。標簽確定有效負載的結(jié)構(gòu)。
階段
連接有四個不同的階段:
- banner
- 認證幀交換
- 消息流握手幀交換
- 消息幀交換
BANNER
客戶端和服務(wù)器在連接時都發(fā)送banner:
"ceph %x %x\n", protocol_features_suppored, protocol_features_required
協(xié)議功能是一個新的,獨特的命名空間。最初沒有定義或要求任何功能,因此這將是“ceph 0 0n”。
如果遠程方需求的功能我們不支持,可以斷開連接。

幀格式
發(fā)送或接收的所有其他數(shù)據(jù)都包含在幀中。每個框架都有以下形式:
frame_len (le32)
tag (TAG_* le32)
frame_header_checksum (le32)
payload
[payload padding -- only present after stream auth phase]
[signature -- only present after stream auth phase]
- frame_header_checksum 是frame_len和tag(8個字節(jié))。
- frame_len包括frame_len le32之后的所有內(nèi)容,直到幀的末尾(所有payloads,signatures和padding)。
- 有payloads格式和長度由tag確定。
- 僅當驗證階段已完成(已發(fā)送TAG_AUTH_DONE)且已啟用簽名時,才會顯示簽名部分。
HELLO
-
TAG_HELLO:client-> server和server-> client:
__u8 entity_type entity_addr_t peer_socket_address- 共享entity_type跟peer_socket_address(這對于檢測我們的有效IP地址非常有用,尤其是在存在NAT的情況下)。
AUTHENTICATION
-
TAG_AUTH_REQUEST:client-> server:
__le32 method; // CEPH_AUTH_{NONE, CEPHX, ...} __le32 num_preferred_modes; list<__le32> mode // CEPH_CON_MODE_* method specific payload -
TAG_AUTH_BAD_METHOD server-> client:拒絕客戶端選擇的auth方法:
__le32 method __le32 negative error result code __le32 num_methods list<__le32> allowed_methods // CEPH_AUTH_{NONE, CEPHX, ...} __le32 num_modes list<__le32> allowed_modes // CEPH_CON_MODE_*- 返回嘗試的auth方法和錯誤代碼(如果不支持該方法,則為-EOPNOTSUPP),以及允許的身份驗證方法列表。
-
TAG_AUTH_REPLY_MORE:server-> client:
__le32 len; method specific payload -
TAG_AUTH_REQUEST_MORE:client-> server:
__le32 len; method specific payload -
TAG_AUTH_DONE :(server-> client):
__le64 global_id __le32 connection mode // CEPH_CON_MODE_* method specific payload- 服務(wù)器是決定身份驗證已完成以及最終連接模式。
客戶端使用允許的身份驗證方法時的身份驗證階段交互示例:

客戶端使用禁用身份驗證方法作為第一次嘗試時的身份驗證階段交互示例:

授權(quán)后幀格式
幀格式是固定的(見上文),但可以采用三種不同的形式,具體取決于AUTH_DONE標志:
-
如果既未指定FLAG_SIGNED或FLAG_ENCRYPTED,就很簡單:
frame_len tag payload payload_padding (out to auth block_size)- 填充是 bytes < auth block_size部分,它將payload + payload_padding的總長度帶到block_size的倍數(shù)。它不包括frame_len或標記。填充內(nèi)容可以是零或最好是隨機字節(jié)。
-
如果指定了FLAG_SIGNED:
frame_len tag payload payload_padding (out to auth block_size) signature (sig_size bytes)這里的填充只會讓簽名更高效。它可以隨機數(shù)據(jù)添加額外的混淆。另請注意,簽名輸入必須包含會話密鑰和先前消息中的某些狀態(tài)。
-
如果指定了FLAG_ENCRYPTED:
frame_len tag { payload payload_padding (out to auth block_size) } ^ stream cipher請注意,填充確??値莂uth方法的block_size的倍數(shù),以便可以通過線路發(fā)送消息,而無需等待流中的下一幀。
消息流握手
在此階段,對等體彼此識別并且(如果需要)重新連接到已建立的會話。
-
TAG_CLIENT_IDENT(client->server):標識自己:
__le32 num_addrs entity_addrvec_t*num_addrs entity addrs entity_addr_t target entity addr __le64 gid (numeric part of osd.0, client.123456, ...) __le64 global_seq __le64 features supported (CEPH_FEATURE_* bitmask) __le64 features required (CEPH_FEATURE_* bitmask) __le64 flags (CEPH_MSG_CONNECT_* bitmask) __le64 cookie- 客戶端會先發(fā)送,服務(wù)器會回復相同。如果這是一個新會話,客戶端和服務(wù)器可以繼續(xù)進行消息交換。
- 目標addr是客戶端嘗試連接進程地址,如果客戶端正在與錯誤的守護進程通信,則服務(wù)器端可以關(guān)閉連接。
- type.gid(entity_name_t)通過將hello frame 中共享的類型與gid組合在一起 。這表示我們不需要放在每條消息的header中。我們也無法從其他entity_name_t發(fā)送消息。這個將此設(shè)置在_send_message等的頂部,這不會破壞任何現(xiàn)有functionality。希望根據(jù)經(jīng)過身份驗證的憑據(jù)允許來規(guī)避此實現(xiàn)。
- cookie是用于標識會話的客戶端coookie,可用于重新連接到現(xiàn)有會話。
- 我們從msgr1中刪除了'protocol_version'字段
-
TAG_IDENT_MISSING_FEATURES(server->client):功能太少的TAG_IDENT:
__le64 features we require that the peer didn't advertise -
TAG_SERVER_IDENT(server-> client):接受客戶端身份并識別服務(wù)器:
__le32 num_addrs entity_addrvec_t*num_addrs entity addrs __le64 gid (numeric part of osd.0, client.123456, ...) __le64 global_seq __le64 features supported (CEPH_FEATURE_* bitmask) __le64 features required (CEPH_FEATURE_* bitmask) __le64 flags (CEPH_MSG_CONNECT_* bitmask) __le64 cookie- 如果客戶端稍后斷開連接并想要重新連接會話,則客戶端可以使用服務(wù)器cookie。
-
TAG_RECONNECT(client->server):重新連接到已建立的會話:
__le32 num_addrs entity_addr_t * num_addrs __le64 client_cookie __le64 server_cookie __le64 global_seq __le64 connect_seq __le64 msg_seq (the last msg seq received) -
TAG_RECONNECT_OK(server-> client):進行確認重新連接:
__le64 msg_seq (last msg seq received)- 一旦客戶端收到此消息,客戶端就可以進行消息交換。
- 一旦服務(wù)器發(fā)送了這個,服務(wù)器就可以進行消息交換。
TAG_RECONNECT_RETRY_SESSION(僅限服務(wù)器):由于舊的connect_seq而導致重新連接失敗
TAG_RECONNECT_RETRY_GLOBAL(僅限服務(wù)器):由于舊的global_seq而導致重新連接失敗
-
TAG_RECONNECT_WAIT(僅限服務(wù)器):由于connect race導致重新連接失敗。
- 表示服務(wù)器已連接到客戶端,該方向應(yīng)該贏得比賽。客戶端應(yīng)該等待該連接完成。
-
TAG_RESET_SESSION(僅限服務(wù)器):要求客戶端重置會話:
__u8 full- full flag表示對等體是否應(yīng)該執(zhí)行完全重置,即丟棄消息隊列。
失敗場景示例:
- 第一個客戶端的client_ident消息丟失,然后客戶端重新連接。

- 服務(wù)器的server_ident消息丟失,然后客戶端重新連接。

- 服務(wù)器的server_ident消息丟失,然后服務(wù)器重新連接。

- 會話建立后連接失敗,然后客戶端重新連接。

- 建立會話后連接失敗,因為服務(wù)器重置,然后客戶端重新連接。

RC *表示重置會話滿標志取決于連接的policy.resetcheck。
- 建立會話后連接失敗,因為客戶端重置,然后客戶端重新連接。

消息交換
會話建立后,我們可以交換消息。
-
TAG_MSG:一條消息:
ceph_msg_header2 front middle data_pre_padding data-
ceph_msg_header2是從ceph_msg_header修改的:
- 包括一個ack_seq。這避免了大多數(shù)時候需要TAG_ACK消息。
- 刪除src字段,我們現(xiàn)在從消息流握手(TAG_IDENT)中獲取該字段。
- 指定data_pre_padding長度,可用于調(diào)整數(shù)據(jù)有效負載的對齊方式。(NOTE: is this is useful?)
-
-
TAG_ACK:確認收到消息:
__le64 seq- 這僅用于有狀態(tài)會話。
-
TAG_KEEPALIVE2:檢查連接活躍度:
ceph_timespec stamp- 時間戳是Sender本地的。
-
TAG_KEEPALIVE2_ACK:回復keepalive2:
ceph_timestamp stamp- 時間戳來自我們正在響應(yīng)的TAG_KEEPALIVE2。
-
TAG_CLOSE:終止連接
表示應(yīng)終止連接。這相當于掛斷或重置(即應(yīng)該觸發(fā)ms_handle_reset)。它不是嚴格必要或有用的,因為我們可以斷開TCP連接。
協(xié)議交互(WIP)
