From patchwork Mon Jan 25 22:24:44 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Xu X-Patchwork-Id: 8116821 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 2C242BEEE5 for ; Mon, 25 Jan 2016 23:07:01 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6E7F920389 for ; Mon, 25 Jan 2016 23:07:00 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 096F920396 for ; Mon, 25 Jan 2016 23:06:59 +0000 (UTC) Received: from localhost ([::1]:41205 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aNqDq-0000mM-BM for patchwork-qemu-devel@patchwork.kernel.org; Mon, 25 Jan 2016 18:06:58 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34516) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aNpZt-0003lY-F7 for qemu-devel@nongnu.org; Mon, 25 Jan 2016 17:25:42 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aNpZs-00089D-5A for qemu-devel@nongnu.org; Mon, 25 Jan 2016 17:25:41 -0500 Received: from mx1.redhat.com ([209.132.183.28]:40449) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aNpZr-00088c-Tn for qemu-devel@nongnu.org; Mon, 25 Jan 2016 17:25:40 -0500 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (Postfix) with ESMTPS id 864395709 for ; Mon, 25 Jan 2016 22:25:39 +0000 (UTC) Received: from wei-thinkpad.nay.redhat.com (vpn1-5-80.pek2.redhat.com [10.72.5.80]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0PMOxvq001754; Mon, 25 Jan 2016 17:25:33 -0500 From: wexu@redhat.com To: qemu-devel@nongnu.org Date: Tue, 26 Jan 2016 06:24:44 +0800 Message-Id: <1453760690-21221-5-git-send-email-wexu@redhat.com> In-Reply-To: <1453760690-21221-1-git-send-email-wexu@redhat.com> References: <1453760690-21221-1-git-send-email-wexu@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 X-Mailman-Approved-At: Mon, 25 Jan 2016 18:03:51 -0500 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 04/10] Tcp general data coalescing, the parameters is a little bit horrible, it's complicated to read, should can be optimized later. 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+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Wei Xu --- hw/net/virtio-net.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 7a6cd4c..d005a56 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -41,6 +41,10 @@ #define VIRTIO_HEADER 12 /* Virtio net header size */ #define IP_OFFSET (VIRTIO_HEADER + sizeof(struct eth_header)) +#define TCP_WINDOW 65535 + +/* ip4 max payload, 16 bits in the header */ +#define MAX_IP4_PAYLOAD (65535 - sizeof(struct ip_header)) #define MAX_VIRTIO_IP_PAYLOAD (65535 + IP_OFFSET) @@ -1670,11 +1674,130 @@ out: return 0; } +static int32_t virtio_net_rsc_handle_ack(NetRscChain *chain, NetRscSeg *seg, + const uint8_t *buf, struct tcp_header *n_tcp, + struct tcp_header *o_tcp) +{ + uint32_t nack, oack; + uint16_t nwin, owin; + + nack = htonl(n_tcp->th_ack); + nwin = htons(n_tcp->th_win); + oack = htonl(o_tcp->th_ack); + owin = htons(o_tcp->th_win); + + if ((nack - oack) >= TCP_WINDOW) { + return RSC_FINAL; + } else if (nack == oack) { + /* duplicated ack or window probe */ + if (nwin == owin) { + /* duplicated ack, add dup ack count due to whql test up to 1 */ + + if (seg->dup_ack_count == 0) { + seg->dup_ack_count++; + return RSC_COALESCE; + } else { + /* Spec says should send it directly */ + return RSC_FINAL; + } + } else { + /* Coalesce window update */ + o_tcp->th_win = n_tcp->th_win; + return RSC_COALESCE; + } + } else { + /* pure ack, update ack */ + o_tcp->th_ack = n_tcp->th_ack; + return RSC_COALESCE; + } +} + +static int32_t virtio_net_rsc_coalesce_tcp(NetRscChain *chain, NetRscSeg *seg, + const uint8_t *buf, struct tcp_header *n_tcp, uint16_t n_tcp_len, + uint16_t n_data, struct tcp_header *o_tcp, uint16_t o_tcp_len, + uint16_t o_data, uint16_t *p_ip_len, uint16_t max_data) +{ + void *data; + uint16_t o_ip_len; + uint32_t nseq, oseq; + + o_ip_len = htons(*p_ip_len); + nseq = htonl(n_tcp->th_seq); + oseq = htonl(o_tcp->th_seq); + + /* Ignore packet with more/larger tcp options */ + if (n_tcp_len > o_tcp_len) { + return RSC_FINAL; + } + + /* out of order or retransmitted. */ + if ((nseq - oseq) > TCP_WINDOW) { + return RSC_FINAL; + } + + data = ((uint8_t *)n_tcp) + n_tcp_len; + if (nseq == oseq) { + if ((0 == o_data) && n_data) { + /* From no payload to payload, normal case, not a dup ack or etc */ + goto coalesce; + } else { + return virtio_net_rsc_handle_ack(chain, seg, buf, n_tcp, o_tcp); + } + } else if ((nseq - oseq) != o_data) { + /* Not a consistent packet, out of order */ + return RSC_FINAL; + } else { +coalesce: + if ((o_ip_len + n_data) > max_data) { + return RSC_FINAL; + } + + /* Here comes the right data, the payload lengh in v4/v6 is different, + so use the field value to update */ + *p_ip_len = htons(o_ip_len + n_data); /* Update new data len */ + o_tcp->th_offset_flags = n_tcp->th_offset_flags; /* Bring 'PUSH' big */ + o_tcp->th_ack = n_tcp->th_ack; + o_tcp->th_win = n_tcp->th_win; + + memmove(seg->buf + seg->size, data, n_data); + seg->size += n_data; + return RSC_COALESCE; + } +} static int32_t virtio_net_rsc_try_coalesce4(NetRscChain *chain, NetRscSeg *seg, const uint8_t *buf, size_t size) { - return RSC_FINAL; + uint16_t o_ip_len, n_ip_len; /* len in ip header field */ + uint16_t n_ip_hdrlen, o_ip_hdrlen; /* ipv4 header len */ + uint16_t n_tcp_len, o_tcp_len; /* tcp header len */ + uint16_t o_data, n_data; /* payload without virtio/eth/ip/tcp */ + struct ip_header *n_ip, *o_ip; + struct tcp_header *n_tcp, *o_tcp; + + n_ip = (struct ip_header *)(buf + IP_OFFSET); + n_ip_hdrlen = ((0xF & n_ip->ip_ver_len) << 2); + n_ip_len = htons(n_ip->ip_len); + n_tcp = (struct tcp_header *)(((uint8_t *)n_ip) + n_ip_hdrlen); + n_tcp_len = (htons(n_tcp->th_offset_flags) & 0xF000) >> 10; + n_data = n_ip_len - n_ip_hdrlen - n_tcp_len; + + o_ip = (struct ip_header *)(seg->buf + IP_OFFSET); + o_ip_hdrlen = ((0xF & o_ip->ip_ver_len) << 2); + o_ip_len = htons(o_ip->ip_len); + o_tcp = (struct tcp_header *)(((uint8_t *)o_ip) + o_ip_hdrlen); + o_tcp_len = (htons(o_tcp->th_offset_flags) & 0xF000) >> 10; + o_data = o_ip_len - o_ip_hdrlen - o_tcp_len; + + if ((n_ip->ip_src ^ o_ip->ip_src) || (n_ip->ip_dst ^ o_ip->ip_dst) + || (n_tcp->th_sport ^ o_tcp->th_sport) + || (n_tcp->th_dport ^ o_tcp->th_dport)) { + return RSC_NO_MATCH; + } + + return virtio_net_rsc_coalesce_tcp(chain, seg, buf, + n_tcp, n_tcp_len, n_data, o_tcp, o_tcp_len, + o_data, &o_ip->ip_len, MAX_IP4_PAYLOAD); } static size_t virtio_net_rsc_callback(NetRscChain *chain, NetClientState *nc,