From patchwork Wed Oct 21 11:27:56 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark McLoughlin X-Patchwork-Id: 36551 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 4EF56B7C1A for ; Thu, 22 Oct 2009 00:13:53 +1100 (EST) Received: from localhost ([127.0.0.1]:46933 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1N0b0g-0003Yn-6c for incoming@patchwork.ozlabs.org; Wed, 21 Oct 2009 09:13:50 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1N0Zcs-0007BL-5j for qemu-devel@nongnu.org; Wed, 21 Oct 2009 07:45:10 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1N0Zcn-00078k-IR for qemu-devel@nongnu.org; Wed, 21 Oct 2009 07:45:09 -0400 Received: from [199.232.76.173] (port=48982 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1N0Zcn-00078Y-Bm for qemu-devel@nongnu.org; Wed, 21 Oct 2009 07:45:05 -0400 Received: from mx1.redhat.com ([209.132.183.28]:26022) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1N0Zcm-0005rO-OU for qemu-devel@nongnu.org; Wed, 21 Oct 2009 07:45:05 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id n9LBToYW009303; Wed, 21 Oct 2009 07:29:50 -0400 Received: from blaa.localdomain (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id n9LBTmST025676; Wed, 21 Oct 2009 07:29:50 -0400 Received: by blaa.localdomain (Postfix, from userid 500) id 60CCF463FA; Wed, 21 Oct 2009 12:27:59 +0100 (IST) From: Mark McLoughlin To: qemu-devel@nongnu.org Date: Wed, 21 Oct 2009 12:27:56 +0100 Message-Id: <1256124478-2988-18-git-send-email-markmc@redhat.com> In-Reply-To: <1256124478-2988-1-git-send-email-markmc@redhat.com> References: <1256124478-2988-1-git-send-email-markmc@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 X-detected-operating-system: by monty-python.gnu.org: Genre and OS details not recognized. Cc: Mark McLoughlin , Anthony Liguori Subject: [Qemu-devel] [PATCH 17/19] Work around dhclient brokenness X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Anthony Liguori With the latest GSO/csum offload patches, any guest using an unpatched version of dhclient (any Ubuntu guest, for instance), will no longer be able to get a DHCP address. dhclient is actually at fault here. It uses AF_PACKET to receive DHCP responses but does not check auxdata to see if the packet has a valid csum. This causes it to throw out the DHCP responses it gets from the virtio interface as there is not a valid checksum. Fedora has carried a patch to fix their dhclient (it's needed for Xen too) but this patch has not made it into a release of dhclient. AFAIK, the patch is in the dhclient CVS but I cannot confirm since their CVS is not public. This patch, suggested by Rusty, looks for UDP packets (of a normal MTU) and explicitly adds a checksum to them if they are missing one. This allows unpatched dhclients to continue to work without needing to update the guest kernels. Signed-off-by: Anthony Liguori Signed-off-by: Mark McLoughlin --- hw/virtio-net.c | 29 +++++++++++++++++++++++++++++ 1 files changed, 29 insertions(+), 0 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 19d00a6..4590594 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -369,6 +369,34 @@ static int virtio_net_can_receive(VLANClientState *vc) return do_virtio_net_can_receive(n, VIRTIO_NET_MAX_BUFSIZE); } +/* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so + * it never finds out that the packets don't have valid checksums. This + * causes dhclient to get upset. Fedora's carried a patch for ages to + * fix this with Xen but it hasn't appeared in an upstream release of + * dhclient yet. + * + * To avoid breaking existing guests, we catch udp packets and add + * checksums. This is terrible but it's better than hacking the guest + * kernels. + * + * N.B. if we introduce a zero-copy API, this operation is no longer free so + * we should provide a mechanism to disable it to avoid polluting the host + * cache. + */ +static void work_around_broken_dhclient(struct virtio_net_hdr *hdr, + const uint8_t *buf, size_t size) +{ + if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */ + (size > 27 && size < 1500) && /* normal sized MTU */ + (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */ + (buf[23] == 17) && /* ip.protocol == UDP */ + (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */ + /* FIXME this cast is evil */ + net_checksum_calculate((uint8_t *)buf, size); + hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM; + } +} + static int iov_fill(struct iovec *iov, int iovcnt, const void *buf, int count) { int offset, i; @@ -396,6 +424,7 @@ static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt, if (peer_has_vnet_hdr(n)) { memcpy(hdr, buf, sizeof(*hdr)); offset = sizeof(*hdr); + work_around_broken_dhclient(hdr, buf + offset, size - offset); } /* We only ever receive a struct virtio_net_hdr from the tapfd,