RPCoRDMA: fix reassembly for Position-Zero Read Chunk

A Long Call or Position-Zero Read Chunk (PZRC) MUST include
appropriate XDR roundup padding to maintain proper XDR alignment
of their contents. For a PZRC, padding has already been added to
the payload stream thus all padding added by the InfiniBand layer
must be removed before adding the fragment to the reassembly table.

See: https://tools.ietf.org/html/rfc8166#section-3.5 (Section 3.5.3)

Closes #17054
This commit is contained in:
Jorge Mora 2020-12-02 10:54:37 -07:00 committed by AndersBroman
parent 5ca608f519
commit 31b81393be
3 changed files with 20 additions and 4 deletions

View File

@ -1763,7 +1763,7 @@ dissect_infiniband_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i
/* General Variables */
gboolean bthFollows = FALSE; /* Tracks if we are parsing a BTH. This is a significant decision point */
struct infinibandinfo info = { 0, FALSE, 0, NULL, 0, 0, 0 };
struct infinibandinfo info = { 0, 0, FALSE, 0, NULL, 0, 0, 0 };
gint32 nextHeaderSequence = -1; /* defined by this dissector. #define which indicates the upcoming header sequence from OpCode */
guint8 nxtHdr = 0; /* Keyed off for header dissection order */
guint16 packetLength = 0; /* Packet Length. We track this as tvb_length - offset. */
@ -1912,6 +1912,7 @@ skip_lrh:
bthFollows = TRUE;
/* Get the OpCode - this tells us what headers are following */
info.opCode = tvb_get_guint8(tvb, offset);
info.pad_count = (tvb_get_guint8(tvb, offset+1) & 0x30) >> 4;
if ((info.opCode >> 5) == 0x2) {
info.dctConnect = !(tvb_get_guint8(tvb, offset + 1) & 0x80);
@ -3816,7 +3817,7 @@ static void parse_CM_DRsp(proto_tree *top_tree, packet_info *pinfo, tvbuff_t *tv
static void parse_COM_MGT(proto_tree *parentTree, packet_info *pinfo, tvbuff_t *tvb, gint *offset, proto_tree* top_tree)
{
MAD_Data MadData;
struct infinibandinfo info = { 0, FALSE, 0, NULL, 0, 0, 0 };
struct infinibandinfo info = { 0, 0, FALSE, 0, NULL, 0, 0, 0 };
gint local_offset;
const char *label;
proto_item *CM_header_item;
@ -5971,7 +5972,7 @@ static void dissect_general_info(tvbuff_t *tvb, gint offset, packet_info *pinfo,
MAD_Data MadData;
/* BTH - Base Trasport Header */
struct infinibandinfo info = { 0, FALSE, 0, NULL, 0, 0, 0 };
struct infinibandinfo info = { 0, 0, FALSE, 0, NULL, 0, 0, 0 };
gint bthSize = 12;
void *src_addr, /* the address to be displayed in the source/destination columns */
*dst_addr; /* (lid/gid number) will be stored here */

View File

@ -114,6 +114,7 @@ typedef struct {
*/
struct infinibandinfo {
guint8 opCode; /* OpCode from BTH header. */
guint8 pad_count; /* PadCount from BTH header. */
gboolean dctConnect; /* indicator for DCT connect/disconnect */
guint16 cm_attribute_id; /* attribute id for CM messages */
proto_tree* payload_tree;

View File

@ -203,6 +203,7 @@ typedef struct {
guint32 msgno; /* Message number base so fragments are
sequential between segment requests */
chunk_type_t type; /* Chunk type for segment */
guint32 xdrpos; /* Position in XDR stream -- RDMA read only */
guint32 length; /* Length of segment in bytes */
wmem_array_t *requests; /* List of requests for segment */
} segment_info_t;
@ -485,7 +486,7 @@ static tvbuff_t *add_fragment(tvbuff_t *tvb, gint offset, guint32 msgid,
gint32 msg_num, gboolean more_frags, rdma_conv_info_t *p_rdma_conv_info,
packet_info *pinfo, proto_tree *tree)
{
guint32 nbytes;
guint32 nbytes, frag_size;
tvbuff_t *new_tvb = NULL;
fragment_head *fd_head = NULL;
@ -495,6 +496,18 @@ static tvbuff_t *add_fragment(tvbuff_t *tvb, gint offset, guint32 msgid,
nbytes = tvb_captured_length_remaining(tvb, offset);
if (nbytes > 0 || more_frags) {
/* Add message fragment to reassembly table */
if (gp_infiniband_info->pad_count > 0 && p_rdma_conv_info != NULL && \
p_rdma_conv_info->segment_info != NULL && \
p_rdma_conv_info->segment_info->type == RDMA_READ_CHUNK && \
p_rdma_conv_info->segment_info->xdrpos == 0) {
/* Do not include any padding bytes inserted by Infiniband
* layer if this is a PZRC (Position-Zero Read Chunk) since
* payload stream already has any necessary padding bytes */
frag_size = tvb_reported_length_remaining(tvb, offset) - gp_infiniband_info->pad_count;
if (frag_size < nbytes) {
nbytes = frag_size;
}
}
fd_head = fragment_add_seq_check(&rpcordma_reassembly_table,
tvb, offset, pinfo,
msgid, NULL, (guint32)msg_num,
@ -998,6 +1011,7 @@ process_rdma_list(tvbuff_t *tvb, guint offset, wmem_array_t *p_list,
p_segment_info->msgid = msgid;
p_segment_info->msgno = msg_num + 1;
p_segment_info->type = p_rdma_chunk->type;
p_segment_info->xdrpos = xdrpos;
p_segment_info->length = p_rdma_segment->length;
p_segment_info->requests = wmem_array_new(wmem_file_scope(), sizeof(request_t));
/* Add segment to the list of segments */