From 2bba5eb7044504044b9a0e913e95fa4f542e49e4 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 16 Jan 2015 11:53:29 +0100 Subject: [PATCH] tcp: zero copy fast path in app-layer reassembly Create 2 'fast paths' for app layer reassembly. Both are about reducing copying. In the cases described below, we pass the segment's data directly to the app layer API, instead of first copying it into a buffer than we then pass. This safes a copy. The first is for the case when we have just one single segment that was just ack'd. As we know that we won't use any other segment this round, we can just use the segment data. The second case is more aggressive. When the segment meets a certain size limit (currently hardcoded at 128 bytes), we pass it to the app-layer API directly. Thus invoking the app-layer somewhat more often to safe some copies. --- src/stream-tcp-reassemble.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index bd5c9029fc..b61748dd10 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2572,6 +2572,42 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd, Packet *p) { + /* fast path 1: segment is exactly what we need */ + if (likely(rd->data_len == 0 && SEQ_EQ(seg->seq, rd->ra_base_seq+1) && SEQ_EQ(stream->last_ack, (seg->seq + seg->payload_len)))) { + /* process single segment directly */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + seg->payload, seg->payload_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += seg->payload_len; + rd->ra_base_seq += seg->payload_len; + + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + return 1; + /* fast path 2: segment acked completely, meets minimal size req for 0copy processing */ + } else if (rd->data_len == 0 && SEQ_EQ(seg->seq, rd->ra_base_seq+1) && SEQ_GT(stream->last_ack, (seg->seq + seg->payload_len)) && seg->payload_len >= 128) { + /* process single segment directly */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + seg->payload, seg->payload_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += seg->payload_len; + rd->ra_base_seq += seg->payload_len; + + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + return 1; + } + uint16_t payload_offset = 0; uint16_t payload_len = 0;