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.
pull/1315/head
Victor Julien 11 years ago
parent 8c1bc7cfb6
commit 2bba5eb704

@ -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;

Loading…
Cancel
Save