From patchwork Sun Jan 31 18:13:28 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Xu X-Patchwork-Id: 8174741 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 6567EBEEE5 for ; Sun, 31 Jan 2016 18:16:01 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A50C920351 for ; Sun, 31 Jan 2016 18:16: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 B5B672034E for ; Sun, 31 Jan 2016 18:15:59 +0000 (UTC) Received: from localhost ([::1]:42722 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aPwXW-0005xu-Rt for patchwork-qemu-devel@patchwork.kernel.org; Sun, 31 Jan 2016 13:15:58 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36810) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aPwVw-0002zY-Au for qemu-devel@nongnu.org; Sun, 31 Jan 2016 13:14:21 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aPwVv-0006Ck-6l for qemu-devel@nongnu.org; Sun, 31 Jan 2016 13:14:20 -0500 Received: from mx1.redhat.com ([209.132.183.28]:49116) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aPwVu-0006Ca-Vp for qemu-devel@nongnu.org; Sun, 31 Jan 2016 13:14:19 -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 B3AC0C057EC9 for ; Sun, 31 Jan 2016 18:14:18 +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 u0VIDVgV014091; Sun, 31 Jan 2016 13:14:15 -0500 From: wexu@redhat.com To: qemu-devel@nongnu.org Date: Mon, 1 Feb 2016 02:13:28 +0800 Message-Id: <1454264009-24094-10-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: Wei Xu , 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 09/10] virtio-net rsc: Add IPv6 support 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 From: Wei Xu A few more stuffs should be included to support this 1. Corresponding chain lookup 2. Coalescing callback for the protocol chain 3. Filter & Sanity Check. Signed-off-by: Wei Xu --- hw/net/virtio-net.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 9b44762..c9f6bfc 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -46,12 +46,19 @@ #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 IP6_ADDR_OFFSET (IP_OFFSET + 8) /* ipv6 address start */ +#define TCP6_OFFSET (IP_OFFSET + sizeof(struct ip6_header)) /* tcp6 header */ +#define TCP6_PORT_OFFSET TCP6_OFFSET /* tcp6 port offset */ +#define IP6_ADDR_SIZE 32 /* ipv6 saddr + daddr */ #define TCP_PORT_SIZE 4 /* sport + dport */ #define TCP_WINDOW 65535 /* IPv4 max payload, 16 bits in the header */ #define MAX_IP4_PAYLOAD (65535 - sizeof(struct ip_header)) +/* ip6 max payload, payload in ipv6 don't include the header */ +#define MAX_IP6_PAYLOAD 65535 #define MAX_VIRTIO_IP_PAYLOAD (65535 + IP_OFFSET) /* Purge coalesced packets timer interval */ @@ -1856,6 +1863,42 @@ static int32_t virtio_net_rsc_try_coalesce4(NetRscChain *chain, o_data, &o_ip->ip_len, MAX_IP4_PAYLOAD); } +static int32_t virtio_net_rsc_try_coalesce6(NetRscChain *chain, + NetRscSeg *seg, const uint8_t *buf, size_t size) +{ + uint16_t o_ip_len, n_ip_len; /* len in ip header field */ + uint16_t n_tcp_len, o_tcp_len; /* tcp header len */ + uint16_t o_data, n_data; /* payload without virtio/eth/ip/tcp */ + struct ip6_header *n_ip, *o_ip; + struct tcp_header *n_tcp, *o_tcp; + + n_ip = (struct ip6_header *)(buf + IP_OFFSET); + n_ip_len = htons(n_ip->ip6_ctlun.ip6_un1.ip6_un1_plen); + n_tcp = (struct tcp_header *)(((uint8_t *)n_ip)\ + + sizeof(struct ip6_header)); + n_tcp_len = (htons(n_tcp->th_offset_flags) & 0xF000) >> 10; + n_data = n_ip_len - n_tcp_len; + + o_ip = (struct ip6_header *)(seg->buf + IP_OFFSET); + o_ip_len = htons(o_ip->ip6_ctlun.ip6_un1.ip6_un1_plen); + o_tcp = (struct tcp_header *)(((uint8_t *)o_ip)\ + + sizeof(struct ip6_header)); + o_tcp_len = (htons(o_tcp->th_offset_flags) & 0xF000) >> 10; + o_data = o_ip_len - o_tcp_len; + + if (memcmp(&n_ip->ip6_src, &o_ip->ip6_src, sizeof(struct in6_address)) + || memcmp(&n_ip->ip6_dst, &o_ip->ip6_dst, sizeof(struct in6_address)) + || (n_tcp->th_sport ^ o_tcp->th_sport) + || (n_tcp->th_dport ^ o_tcp->th_dport)) { + return RSC_NO_MATCH; + } + + /* There is a difference between payload lenght in ipv4 and v6, + ip header is excluded in ipv6 */ + 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->ip6_ctlun.ip6_un1.ip6_un1_plen, MAX_IP6_PAYLOAD); +} /* Pakcets with 'SYN' should bypass, other flag should be sent after drain * to prevent out of order */ @@ -2015,6 +2058,59 @@ static size_t virtio_net_rsc_receive4(void *opq, NetClientState* nc, virtio_net_rsc_try_coalesce4); } +static int32_t virtio_net_rsc_filter6(NetRscChain *chain, struct ip6_header *ip, + const uint8_t *buf, size_t size) +{ + uint16_t ip_len; + + if (size < (TCP6_OFFSET + sizeof(tcp_header))) { + return RSC_BYPASS; + } + + if (0x6 != (0xF & ip->ip6_ctlun.ip6_un1.ip6_un1_flow)) { + return RSC_BYPASS; + } + + /* Both option and protocol is checked in this */ + if (ip->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_TCP) { + return RSC_BYPASS; + } + + /* Sanity check */ + ip_len = htons(ip->ip6_ctlun.ip6_un1.ip6_un1_plen); + if (ip_len < sizeof(struct tcp_header) + || ip_len > (size - TCP6_OFFSET)) { + return RSC_BYPASS; + } + + return 0; +} + +static size_t virtio_net_rsc_receive6(void *opq, NetClientState* nc, + const uint8_t *buf, size_t size) +{ + int32_t ret; + NetRscChain *chain; + struct ip6_header *ip; + + chain = (NetRscChain *)opq; + ip = (struct ip6_header *)(buf + IP_OFFSET); + if (RSC_WANT != virtio_net_rsc_filter6(chain, ip, buf, size)) { + return virtio_net_do_receive(nc, buf, size); + } + + ret = virtio_net_rsc_parse_tcp_ctrl((uint8_t *)ip, sizeof(*ip)); + 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, IP6_ADDR_OFFSET, + IP6_ADDR_SIZE, TCP6_PORT_OFFSET, TCP_PORT_SIZE); + } + + return virtio_net_rsc_callback(chain, nc, buf, size, + virtio_net_rsc_try_coalesce6); +} + static NetRscChain *virtio_net_rsc_lookup_chain(NetClientState *nc, uint16_t proto) { @@ -2023,7 +2119,7 @@ static NetRscChain *virtio_net_rsc_lookup_chain(NetClientState *nc, NICState *nic; /* Only handle IPv4/6 */ - if (proto != (uint16_t)ETH_P_IP) { + if ((proto != (uint16_t)ETH_P_IP) && (proto != (uint16_t)ETH_P_IPV6)) { return NULL; } @@ -2044,7 +2140,11 @@ static NetRscChain *virtio_net_rsc_lookup_chain(NetClientState *nc, chain->proto = proto; chain->drain_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, virtio_net_rsc_purge, chain); - chain->do_receive = virtio_net_rsc_receive4; + if (ETH_P_IP == proto) { + chain->do_receive = virtio_net_rsc_receive4; + } else { + chain->do_receive = virtio_net_rsc_receive6; + } QTAILQ_INIT(&chain->buffers); QTAILQ_INSERT_TAIL(&n->rsc_chains, chain, next);