.. Licensed under the OpenIB.org BSD license (FreeBSD Variant) - See COPYING.md
rsocket Protocol and Design Guide               11/11/2012

Data Streaming (TCP) Overview
-----------------------------
Rsockets is a protocol over RDMA that supports a socket-level API
for applications.  For details on the current state of the
implementation, readers should refer to the rsocket man page.  This
document describes the rsocket protocol, general design, and
some implementation details. 

Rsockets exchanges data by performing RDMA write operations into
exposed data buffers.  In addition to RDMA write data, rsockets uses
small, 32-bit messages for internal communication.  RDMA writes
are used to transfer application data into remote data buffers
and to notify the peer when new target data buffers are available.
The following figure highlights the operation.

   host A                   host B
                          remote SGL                      
  target SGL  <-------------  [  ]
     [  ] ------
     [  ] --    ------   receive buffer(s)         
            --        ----->  +--+
              --              |  |
                --            |  |
                  --          |  |
                    --        +--+
                      --       
                        --->  +--+
                              |  |
                              |  |
                              +--+

The remote SGL contains the address, size, and rkey of the target SGL.  As
receive buffers become available on host B, rsockets will issue an RDMA
write against one of the entries in the target SGL on host A.  The
updated entry will reference an available receive buffer.  Immediate data
included with the RDMA write will indicate to host A that a target SGE
has been updated.

When host A has data to send, it will check its target SGL.  The current
target SGE will contain the address, size, and rkey of the next receive
buffer on host B.  If the data transfer is smaller than the size of the
remote receive buffer, host A will update its target SGE to reflect the
remaining size of the receive buffer.  That is, once a receive buffer has
been published to a remote peer, it will be fully consumed before a second
buffer is used.

Rsockets relies on immediate data to notify the remote peer when data has
been transferred or when a target SGL has been updated.  Because immediate
data requires that the remote QP have a posted receive, rsockets also uses
a credit based flow control mechanism.  The number of credits is based on
the size of the receive queue, with initial credits exchanged during
connection setup.  In order to transfer data, rsockets requires both
available receive buffers (published via the target SGL) and data credits.

Since immediate data is limited to 32-bits, messages may either indicate
the arrival of application data or may be an internal message, but not both.
To avoid credit deadlock, rsockets reserves a small number of available
credits for control messages only, with the protocol relying on RNR NAKs
and retries to make forward progress.


Connection Establishment
------------------------
rsockets uses the RDMA CM for connection establishment.  Struct rs_conn_data
is exchanged during the connection exchange as private data in the request
and reply messages.

struct rs_sge {
	uint64_t addr;
	uint32_t key;
	uint32_t length;
};

#define RS_CONN_FLAG_NET 1

struct rs_conn_data {
	uint8_t		  version;
	uint8_t		  flags;
	uint16_t	  credits;
	uint32_t	  reserved2;
	struct rs_sge target_sgl;
	struct rs_sge data_buf;
};

Version - current version is 1
Flags
RS_CONN_FLAG_NET - Set to 1 if host is big Endian.
                   Determines byte ordering for RDMA write messages
Credits - number of initial receive credits
Reserved2 - set to 0
Target SGL - Address, size (# entries), and rkey of target SGL.
             Remote side will copy this into their remote SGL.
Data Buffer - Initial receive buffer address, size (in bytes), and rkey.
              Remote side will copy this into their first target SGE.


Message Format
--------------
Rsocket uses RDMA writes with immediate data for all message exchanges.
RDMA writes of 0 length are used if no additional data beyond the message
needs to be exchanged.  Immediate data is limited to 32-bits.  Rsockets
defines the following format for messages.

The upper 3 bits are used to define the type of message being exchanged,
with the meaning of the lower 29 bits determined by the upper bits.

Bits    Message             Meaning of
31:29    Type               Bits 28:0
000    Data Transfer     bytes transferred
001    reserved
010    reserved - used internally, available for future use
011    reserved
100    Credit Update     received credits granted
101    reserved
110    Iomap Updated     index of updated entry
111    Control           control message type

Data Transfer
Indicates that application data has been written into the next available
receive buffer.  The size of the transfer, in bytes, is carried in the lower
bits of the message.

Credit Update
Used to indicate that additional receive buffers and credits are available.
The number of available credits is carried in the lower bits of the message.
A credit update message is also used to indicate that a target SGE has been
updated, in which case the number of additional credits may be 0.  The
receiver of a credit update message must check for updates to the target SGL
by inspecting the contents of the SGL.  The rsocket implementation must take
care not to modify a remote target SGL while it may be in use.  This is done
by tracking when a receive buffer referenced by a remote target SGL has been
filled.

Iomap Updated
Used to indicate that a remote iomap entry was updated.  The updated entry
contains the offset value associated with an address, length, and rkey.  Once
an iomap has been updated, the local application can issue directed IO
transfers against the corresponding remote buffer.

Control Message - DISCONNECT
Indicates that the rsocket connection has been fully disconnected and will no
longer send or receive data.  Data received before the disconnect message was
processed may still be available for reading.
 
Control Message - SHUTDOWN
Indicates that the remote rsocket has shutdown the send side of its
connection.  The recipient of a shutdown message will no longer accept
incoming data, but may still transfer outbound data.


Iomapped Buffers
----------------
Rsockets allows for zero-copy transfers using what it refers to as iomapped
buffers.  Iomapping and direct data placement (zero-copy) transfers are done
using rsocket specific extensions.  The general operation is similar to
that used for normal data transfers described above.

   host A                   host B
                          remote iomap                      
  target iomap  <-----------  [  ]
     [  ] ------
     [  ] --    ------  iomapped buffer(s)         
            --        ----->  +--+
              --              |  |
                --            |  |
                  --          |  |
                    --        +--+
                      --       
                        --->  +--+
                              |  |
                              |  |
                              +--+

The remote iomap contains the address, size, and rkey of the target iomap.  As
the applicaton maps buffers host B to a given rsocket, rsockets will issue an RDMA
write against one of the entries in the target iomap on host A.  The
updated entry will reference an available iomapped buffer.  Immediate data
included with the RDMA write will indicate to host A that a target iomap
has been updated.

When host A wishes to transfer directly into an iomapped buffer, it will check
its target iomap for an offset corresponding to a remotely mapped buffer.  A
matching iomap entry will contain the address, size, and rkey of the target
buffer on host B.  Host A will then issue an RDMA operation against the
registered remote data buffer.

From host A's perspective, the transfer appears as a normal send/write
operation, with the data stream redirected directly into the receiving
application's buffer.



Datagram Overview
-----------------
The rsocket API supports datagram sockets.  Datagram support is handled through an
entirely different protocol and internal implementation.  Unlike connected rsockets,
datagram rsockets are not necessarily bound to a network (IP) address.  A datagram
socket may use any number of network (IP) addresses, including those which map to
different RDMA devices.  As a result, a single datagram rsocket must support
using multiple RDMA devices and ports, and a datagram rsocket references a single
UDP socket, plus zero or more UD QPs.

Rsockets uses headers inserted before user data sent over UDP sockets to resolve
remote UD QP numbers.  When a user first attempts to send a datagram to a remote
address (IP and UDP port), rsockets will take the following steps:

1. Store the destination address into a lookup table.
2. Resolve which local network address should be used when sending
   to the specified destination.
3. Allocate a UD QP on the RDMA device associated with the local address.
4. Send the user's datagram to the remote UDP socket.

A header is inserted before the user's datagram.  The header specifies the
UD QP number associated with the local network address (IP and UDP port) of
the send.

A service thread is used to process messages received on the UDP socket.  This
thread updates the rsocket lookup tables with the remote QPN and path record
data.  The service thread forwards data received on the UDP socket to an
rsocket QP.  After the remote QPN and path records have been resolved, datagram
communication between two nodes are done over the UD QP.

UDP Message Format
------------------
Rsockets uses messages exchanged over UDP sockets to resolve remote QP numbers.
If a user sends a datagram to a remote service and the local rsocket is not
yet configured to send directly to a remote UD QP, the user data is sent over
a UDP socket with the following header inserted before the user data. 

struct ds_udp_header {
	uint32_t	  tag;
	uint8_t		  version;
	uint8_t		  op;
	uint8_t		  length;
	uint8_t		  reserved;
	uint32_t	  qpn;  /* lower 8-bits reserved */
	union {
		uint32_t  ipv4;
		uint8_t   ipv6[16];
	} addr;
};

Tag - Marker used to help identify that the UDP header is present.
#define DS_UDP_TAG 0x55555555

Version - IP address version, either 4 or 6
Op - Indicates message type, used to control the receiver's operation.
     Valid operations are RS_OP_DATA and RS_OP_CTRL.  Data messages
     carry user data, while control messages are used to reply with the
     local QP number.
Length - Size of the UDP header.
QPN - UD QP number associated with sender's IP address and port.
      The sender's address and port is extracted from the received UDP
      datagram.
Addr - Target IP address of the sent datagram.

Once the remote QP information has been resolved, data is sent directly
between UD QPs.  The following header is inserted before any user data that
is transferred over a UD QP.

struct ds_header {
	uint8_t		     version;
	uint8_t		     length;
	uint16_t	     port;
	union {
		uint32_t     ipv4;
		struct {
			uint32_t flowinfo;
			uint8_t  addr[16];
		} ipv6;
	} addr;
};

Verion - IP address version
Length - Size of the header
Port - Associated source address UDP port
Addr - Associated source IP address 