From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: passt.top; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=NHOt1NFi; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by passt.top (Postfix) with ESMTPS id 748B25A0626 for ; Mon, 23 Mar 2026 19:01:56 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774288915; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=DAiVevu5bviN+AorPMLNGj5bKWRvTGWFnoX3FnJcDm8=; b=NHOt1NFiQtKKJWOKTP4I5/xvDDaIQN0YS1sHwLC7H1BkZMsE03l42uqjU9u1cAsT8eQAt5 28qy7fvABS9jdd6aaFhZ/YfNDEaS5pPHKQ/bUYSG6FUdED8q1067gumQTiRHOmB7oeIZvU 9nWmqmDqye9i/kUfcc+KbCyl/viqxyM= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-2-D_S5qYf0MwiRViYEviNHag-1; Mon, 23 Mar 2026 14:01:53 -0400 X-MC-Unique: D_S5qYf0MwiRViYEviNHag-1 X-Mimecast-MFC-AGG-ID: D_S5qYf0MwiRViYEviNHag_1774288912 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7818619560A2 for ; Mon, 23 Mar 2026 18:01:52 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.32.96]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 58EF61955D71; Mon, 23 Mar 2026 18:01:51 +0000 (UTC) From: Laurent Vivier To: passt-dev@passt.top Subject: [PATCH] vhost_user: Offer VIRTIO_NET_F_GUEST_CSUM Date: Mon, 23 Mar 2026 19:01:49 +0100 Message-ID: <20260323180149.1268399-1-lvivier@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: cY5mtkdZh-iioaGV9RhFpxRGbuTzs5RRgXXdpU08sG8_1774288912 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true Message-ID-Hash: PHCCXUZELKYWL5I3QL4XKLUIDKPH3G7B X-Message-ID-Hash: PHCCXUZELKYWL5I3QL4XKLUIDKPH3G7B X-MailFrom: lvivier@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Laurent Vivier X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: According to the virtio-net specification, when the VIRTIO_NET_F_GUEST_CSUM is negotiated, the device can set VIRTIO_NET_HDR_F_DATA_VALID in the virtio-net header to indicate that packet checksums have been validated, allowing the guest to skip verification. Without this feature, the device must provide fully checksummed packets. The vhost-user TCP and UDP paths were unconditionally skipping checksum computation, regardless of whether GUEST_CSUM was negotiated. This went undetected with Linux guests because Linux's virtio-net driver honours VIRTIO_NET_HDR_F_DATA_VALID regardless of whether VIRTIO_NET_F_GUEST_CSUM was negotiated, marking such packets as CHECKSUM_UNNECESSARY and skipping verification. iPXE, however, does not negotiate GUEST_CSUM, ignores the DATA_VALID flag entirely, and always verifies checksums. This caused TCP connections to fail: the SYN-ACK had a zero TCP checksum, iPXE rejected it, and the connection timed out in SYN_RCVD. Adding --pcap happened to mask the bug, because the pcap code path forces checksum computation to ensure correct captures. Offer VIRTIO_NET_F_GUEST_CSUM in the device features, and only skip checksum computation when the guest has actually negotiated it. When GUEST_CSUM is not negotiated, always compute valid checksums as required by the specification. We keep setting VIRTIO_NET_HDR_F_DATA_VALID unconditionally in VU_HEADER: when GUEST_CSUM is negotiated, the flag lets the guest skip checksum verification; when it is not, the spec says the guest should ignore the flags field, so setting it is harmless. Signed-off-by: Laurent Vivier --- Notes: Based-on: 20260323165259.1253482-1-lvivier@redhat.com tcp_vu.c | 8 ++++++-- udp_vu.c | 6 ++++-- vhost_user.c | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tcp_vu.c b/tcp_vu.c index 776b47aea18c..2ab56f25a9be 100644 --- a/tcp_vu.c +++ b/tcp_vu.c @@ -172,7 +172,9 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags) seq--; payload = IOV_TAIL(flags_elem[0].in_sg, iov_cnt, VNET_HLEN); - tcp_fill_headers(c, conn, CONN_V4(conn), &payload, -1, seq, !*c->pcap); + tcp_fill_headers(c, conn, CONN_V4(conn), &payload, -1, seq, + vu_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM) && + !*c->pcap); if (*c->pcap) pcap_iov(flags_elem[0].in_sg, iov_cnt, VNET_HLEN); @@ -512,7 +514,9 @@ int tcp_vu_data_from_sock(const struct ctx *c, struct tcp_tap_conn *conn) check = -1; previous_dlen = dlen; - tcp_vu_prepare(c, conn, iov, iov_cnt, &check, !*c->pcap, push); + tcp_vu_prepare(c, conn, iov, iov_cnt, &check, + vu_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM) && + !*c->pcap, push); if (*c->pcap) pcap_iov(iov, iov_cnt, VNET_HLEN); diff --git a/udp_vu.c b/udp_vu.c index 80391b4f8788..7ed271403481 100644 --- a/udp_vu.c +++ b/udp_vu.c @@ -223,10 +223,12 @@ void udp_vu_sock_to_tap(const struct ctx *c, int s, int n, flow_sidx_t tosidx) vu_set_vnethdr(iov_vu[0].iov_base, elem_used); iov_drop_header(&data, VNET_HLEN); udp_vu_prepare(c, &data, toside); - if (*c->pcap) { + if (!vu_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM) || + *c->pcap) { udp_vu_csum(toside, &data); - pcap_iov(data.iov, data.cnt, data.off); } + if (*c->pcap) + pcap_iov(data.iov, data.cnt, data.off); vu_flush(vdev, vq, elem, elem_used); } } diff --git a/vhost_user.c b/vhost_user.c index 75665ec6522f..08a7b2d74099 100644 --- a/vhost_user.c +++ b/vhost_user.c @@ -322,6 +322,7 @@ static bool vu_get_features_exec(struct vu_dev *vdev, { uint64_t features = 1ULL << VIRTIO_F_VERSION_1 | + 1ULL << VIRTIO_NET_F_GUEST_CSUM | 1ULL << VIRTIO_NET_F_MRG_RXBUF | 1ULL << VHOST_F_LOG_ALL | 1ULL << VHOST_USER_F_PROTOCOL_FEATURES; -- 2.53.0