From patchwork Sun Jan 31 18:13:26 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Xu X-Patchwork-Id: 576236 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 728B5140BC4 for ; Mon, 1 Feb 2016 05:17:30 +1100 (AEDT) Received: from localhost ([::1]:42744 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aPwYy-0000vC-HK for incoming@patchwork.ozlabs.org; Sun, 31 Jan 2016 13:17:28 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36752) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aPwVm-0002by-8D for qemu-devel@nongnu.org; Sun, 31 Jan 2016 13:14:11 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aPwVl-0006BG-30 for qemu-devel@nongnu.org; Sun, 31 Jan 2016 13:14:10 -0500 Received: from mx1.redhat.com ([209.132.183.28]:36653) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aPwVk-0006BB-RT for qemu-devel@nongnu.org; Sun, 31 Jan 2016 13:14:09 -0500 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id 9039D70D60 for ; Sun, 31 Jan 2016 18:14:08 +0000 (UTC) Received: from wei-thinkpad.nay.redhat.com (vpn1-6-127.pek2.redhat.com [10.72.6.127]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0VIDVgT014091; Sun, 31 Jan 2016 13:14:05 -0500 From: wexu@redhat.com To: qemu-devel@nongnu.org Date: Mon, 1 Feb 2016 02:13:26 +0800 Message-Id: <1454264009-24094-8-git-send-email-wexu@redhat.com> In-Reply-To: <1454264009-24094-1-git-send-email-wexu@redhat.com> References: <1454264009-24094-1-git-send-email-wexu@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: victork@redhat.com, mst@redhat.com, jasowang@redhat.com, yvugenfi@redhat.com, Wei Xu , marcel@redhat.com, dfleytma@redhat.com Subject: [Qemu-devel] [RFC Patch v2 07/10] virtio-net rsc: Checking TCP flag and drain specific connection packets X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Wei Xu Normally it includes 2 typical way to handle a TCP control flag, bypass and finalize, bypass means should be sent out directly, and finalize means the packets should also be bypassed, and this should be done after searching for the same connection packets in the pool and sending all of them out, this is to avoid out of data. All the 'SYN' packets will be bypassed since this always begin a new' connection, other flag such 'FIN/RST' will trigger a finalization, because this normally happens upon a connection is going to be closed. Signed-off-by: Wei Xu --- hw/net/virtio-net.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 88fc4f8..b0987d0 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -41,6 +41,12 @@ #define VIRTIO_HEADER 12 /* Virtio net header size */ #define IP_OFFSET (VIRTIO_HEADER + sizeof(struct eth_header)) + +#define IP4_ADDR_OFFSET (IP_OFFSET + 12) /* ipv4 address start */ +#define TCP4_OFFSET (IP_OFFSET + sizeof(struct ip_header)) /* tcp4 header */ +#define TCP4_PORT_OFFSET TCP4_OFFSET /* tcp4 port offset */ +#define IP4_ADDR_SIZE 8 /* ipv4 saddr + daddr */ +#define TCP_PORT_SIZE 4 /* sport + dport */ #define TCP_WINDOW 65535 /* IPv4 max payload, 16 bits in the header */ @@ -1850,6 +1856,27 @@ static int32_t virtio_net_rsc_try_coalesce4(NetRscChain *chain, o_data, &o_ip->ip_len, MAX_IP4_PAYLOAD); } + +/* Pakcets with 'SYN' should bypass, other flag should be sent after drain + * to prevent out of order */ +static int virtio_net_rsc_parse_tcp_ctrl(uint8_t *ip, uint16_t offset) +{ + uint16_t tcp_flag; + struct tcp_header *tcp; + + tcp = (struct tcp_header *)(ip + offset); + tcp_flag = htons(tcp->th_offset_flags) & 0x3F; + if (tcp_flag & TH_SYN) { + return RSC_BYPASS; + } + + if (tcp_flag & (TH_FIN | TH_URG | TH_RST)) { + return RSC_FINAL; + } + + return 0; +} + static size_t virtio_net_rsc_callback(NetRscChain *chain, NetClientState *nc, const uint8_t *buf, size_t size, VirtioNetCoalesce *coalesce) { @@ -1895,12 +1922,51 @@ static size_t virtio_net_rsc_callback(NetRscChain *chain, NetClientState *nc, return virtio_net_rsc_cache_buf(chain, nc, buf, size); } +/* Drain a connection data, this is to avoid out of order segments */ +static size_t virtio_net_rsc_drain_one(NetRscChain *chain, NetClientState *nc, + const uint8_t *buf, size_t size, uint16_t ip_start, + uint16_t ip_size, uint16_t tcp_port, uint16_t port_size) +{ + NetRscSeg *seg, *nseg; + + QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) { + if (memcmp(buf + ip_start, seg->buf + ip_start, ip_size) + || memcmp(buf + tcp_port, seg->buf + tcp_port, port_size)) { + continue; + } + if ((chain->proto == ETH_P_IP) && seg->is_coalesced) { + virtio_net_rsc_ipv4_checksum(seg); + } + + virtio_net_do_receive(seg->nc, seg->buf, seg->size); + + QTAILQ_REMOVE(&chain->buffers, seg, next); + g_free(seg->buf); + g_free(seg); + break; + } + + return virtio_net_do_receive(nc, buf, size); +} static size_t virtio_net_rsc_receive4(void *opq, NetClientState* nc, const uint8_t *buf, size_t size) { + int32_t ret; + struct ip_header *ip; NetRscChain *chain; chain = (NetRscChain *)opq; + ip = (struct ip_header *)(buf + IP_OFFSET); + + ret = virtio_net_rsc_parse_tcp_ctrl((uint8_t *)ip, + (0xF & ip->ip_ver_len) << 2); + if (RSC_BYPASS == ret) { + return virtio_net_do_receive(nc, buf, size); + } else if (RSC_FINAL == ret) { + return virtio_net_rsc_drain_one(chain, nc, buf, size, IP4_ADDR_OFFSET, + IP4_ADDR_SIZE, TCP4_PORT_OFFSET, TCP_PORT_SIZE); + } + return virtio_net_rsc_callback(chain, nc, buf, size, virtio_net_rsc_try_coalesce4); }