Nautilus 新东西之--MSGR2协议

这是由SimpleMessenger实现的Ceph on-wire protocol的修订版。它解决了性能和安全问题。

目标

修订版protocol有几个与原始protocol相关的目标:

  • 灵活的handshaking。原始协议没有足够灵活的协议协商,2允许不需要的功能。
  • 加密。在线路中进行加密。
  • 性能。我们希望提供协议功能(例如,填充),以便在可能的情况下将计算和内存副本保留在快速路径之外。
  • 签字。我们将允许对流量进行签名(但不一定是加密的)。这可能不会在初始版本中实现。

定义

  • client(C):发起(TCP)连接的一方
  • server(S):接受(TCP)连接的一方
  • connection:两个进程之间的(TCP)连接的实例。
  • entity:一个ceph实体,例如'osd.0'。每个实体凭借“nonce”字段具有一个或多个唯一的entity_addr_t,该字段通常是pid或随机值。
  • session:两个实体之间的有状态会话,其中消息交换是有序的,无损的。如果存在中断(TCP连接断开),则会话可能跨越多个连接。
  • frame:对等体之间发送的离散消息。每个帧由标记(类型代码),有效负载和(如果启用了签名或加密)一些其他字段组成。请参阅下面的结构。
  • tag:与帧关联的类型代码。标签确定有效负载的结构。

阶段

连接有四个不同的阶段:

  1. banner
  2. 认证帧交换
  3. 消息流握手帧交换
  4. 消息帧交换

BANNER

客户端和服务器在连接时都发送banner:

"ceph %x  %x\n", protocol_features_suppored, protocol_features_required

协议功能是一个新的,独特的命名空间。最初没有定义或要求任何功能,因此这将是“ceph 0 0n”。

如果远程方需求的功能我们不支持,可以断开连接。

image

帧格式

发送或接收的所有其他数据都包含在帧中。每个框架都有以下形式:

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个字节)。
  • frame_len包括frame_len le32之后的所有内容,直到帧的末尾(所有payloads,signatures和padding)。
  • 有payloads格式和长度由tag确定。
  • 仅当验证阶段已完成(已发送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
    
    • 服务器是决定身份验证已完成以及最终连接模式。

客户端使用允许的身份验证方法时的身份验证阶段交互示例:

image

客户端使用禁用身份验证方法作为第一次尝试时的身份验证阶段交互示例:

image

授权后帧格式

帧格式是固定的(见上文),但可以采用三种不同的形式,具体取决于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的倍数。它不包括frame_len或标记。填充内容可以是零或最好是随机字节。
  • 如果指定了FLAG_SIGNED:

    frame_len
    tag
    payload
    payload_padding (out to auth block_size)
    signature (sig_size bytes)
    

    这里的填充只会让签名更高效。它可以随机数据添加额外的混淆。另请注意,签名输入必须包含会话密钥和先前消息中的某些状态。

  • 如果指定了FLAG_ENCRYPTED:

    frame_len
    tag
    {
         payload
          payload_padding (out to auth block_size)
      } ^ stream cipher
    

    请注意,填充确保总帧是auth方法的block_size的倍数,以便可以通过线路发送消息,而无需等待流中的下一帧。

消息流握手

在此阶段,对等体彼此识别并且(如果需要)重新连接到已建立的会话。

  • 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
    
    • 客户端会先发送,服务器会回复相同。如果这是一个新会话,客户端和服务器可以继续进行消息交换。
    • 目标addr是客户端尝试连接进程地址,如果客户端正在与错误的守护进程通信,则服务器端可以关闭连接。
    • type.gid(entity_name_t)通过将hello frame 中共享的类型与gid组合在一起 。这表示我们不需要放在每条消息的header中。我们也无法从其他entity_name_t发送消息。这个将此设置在_send_message等的顶部,这不会破坏任何现有functionality。希望根据经过身份验证的凭据允许来规避此实现。
    • cookie是用于标识会话的客户端coookie,可用于重新连接到现有会话。
    • 我们从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):接受客户端身份并识别服务器:

    __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
    
    • 如果客户端稍后断开连接并想要重新连接会话,则客户端可以使用服务器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) 
    
    • 一旦客户端收到此消息,客户端就可以进行消息交换。
    • 一旦服务器发送了这个,服务器就可以进行消息交换。
  • TAG_RECONNECT_RETRY_SESSION(仅限服务器):由于旧的connect_seq而导致重新连接失败

  • TAG_RECONNECT_RETRY_GLOBAL(仅限服务器):由于旧的global_seq而导致重新连接失败

  • TAG_RECONNECT_WAIT(仅限服务器):由于connect race导致重新连接失败。

    • 表示服务器已连接到客户端,该方向应该赢得比赛。客户端应该等待该连接完成。
  • TAG_RESET_SESSION(仅限服务器):要求客户端重置会话:

    __u8 full
    
    • full flag表示对等体是否应该执行完全重置,即丢弃消息队列。

失败场景示例:

  • 第一个客户端的client_ident消息丢失,然后客户端重新连接。
image
  • 服务器的server_ident消息丢失,然后客户端重新连接。
image
  • 服务器的server_ident消息丢失,然后服务器重新连接。
image
  • 会话建立后连接失败,然后客户端重新连接。
image
  • 建立会话后连接失败,因为服务器重置,然后客户端重新连接。
image

RC *表示重置会话满标志取决于连接的policy.resetcheck。

  • 建立会话后连接失败,因为客户端重置,然后客户端重新连接。
image

消息交换

会话建立后,我们可以交换消息。

  • TAG_MSG:一条消息:

    ceph_msg_header2
    front
    middle
    data_pre_padding
    data
    
    • ceph_msg_header2是从ceph_msg_header修改的:

      • 包括一个ack_seq。这避免了大多数时候需要TAG_ACK消息。
      • 删除src字段,我们现在从消息流握手(TAG_IDENT)中获取该字段。
      • 指定data_pre_padding长度,可用于调整数据有效负载的对齐方式。(NOTE: is this is useful?)
  • TAG_ACK:确认收到消息:

      __le64 seq
    
    • 这仅用于有状态会话。
  • TAG_KEEPALIVE2:检查连接活跃度:

    ceph_timespec stamp
    
    • 时间戳是Sender本地的。
  • TAG_KEEPALIVE2_ACK:回复keepalive2:

     ceph_timestamp stamp
    
    • 时间戳来自我们正在响应的TAG_KEEPALIVE2。
  • TAG_CLOSE:终止连接

    表示应终止连接。这相当于挂断或重置(即应该触发ms_handle_reset)。它不是严格必要或有用的,因为我们可以断开TCP连接。

协议交互(WIP)

image

你可能感兴趣的:(Nautilus 新东西之--MSGR2协议)