From nobody Fri Jan 9 00:45:25 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0CA113218DD for ; Mon, 5 Jan 2026 03:45:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767584734; cv=none; b=TUxi3N3e+8l81K1+M5Cr/OwqUw/7LNe5gHH20J48wLhsbMLWGFtJ7JV11lYj1COF8ip7oHczYl0r7CbIarvTb+0cpjmAt48NBTP5XiYJOV4TwqJYD4MDF+tNAgA1ZvvOf0EqwYmQHmB8Hrf37MMKmXlelOkIQk5GvEiCWeMZUbU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767584734; c=relaxed/simple; bh=A9eHKD1wuR2AB7ym2KBl010k+MDToNhmM511fjTVzac=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Cd3GovSyMTkql9Gpk9pr4msKNlcn8PTDy+RW/x7fXd2wAtCUK/WW/bNJ4VgY7tRtvZsZyhiJPqOHBcGSLVJUyZmhxgQaQeq3MdYyDquv4zBLWzXidsMhQGNOBnUAi5JRvG8RuO+A4/2JcSYYieJN2l0QRfAiGKOew8aFAU59SxY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Yt9uXNTB; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Yt9uXNTB" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1767584731; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fvUgZNgE+2O5SZ3XN5OGJVXjV7D5E3bPQGGa5K59U0U=; b=Yt9uXNTB7GvO43ibXSlRxBHbO89gv9Eerp7wXRnAO9U6RlH2fBCItt2oFKfVPsXdgt+7UQ 5/+DIpDHAeWdE2tOHmcIzPmEKuNAZG6sTM7Eg6bGfDh4hCqtp/3Ewj7FzeWGqaPMTuOMzG rEHwYNVR9iXTFC15+sbvp/6j2NFf8R4= Received: from mx-prod-mc-03.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-3-3qkhu5U5Ofml0Xa7Il9O7A-1; Sun, 04 Jan 2026 22:45:25 -0500 X-MC-Unique: 3qkhu5U5Ofml0Xa7Il9O7A-1 X-Mimecast-MFC-AGG-ID: 3qkhu5U5Ofml0Xa7Il9O7A_1767584724 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 64EC219560B2; Mon, 5 Jan 2026 03:45:24 +0000 (UTC) Received: from xudu-thinkpadx1carbongen9.nay.csb (unknown [10.66.60.72]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 832FB180035A; Mon, 5 Jan 2026 03:45:20 +0000 (UTC) From: Xu Du To: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, shuah@kernel.org Cc: netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net-next v3 7/8] selftest: tun: Add test for receiving gso packet from tun Date: Mon, 5 Jan 2026 11:44:42 +0800 Message-ID: In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Content-Type: text/plain; charset="utf-8" The test validate that GSO information are correctly exposed when reading packets from a TUN device. Signed-off-by: Xu Du --- v1 -> v2: - Use previous helper to simplify tunnel packet sending. - Treat read timeout (EAGAIN) as assertion failure. - Correct spelling of 'recieve' to 'receive'. tools/testing/selftests/net/tun.c | 194 ++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) diff --git a/tools/testing/selftests/net/tun.c b/tools/testing/selftests/ne= t/tun.c index dc114237adda..519aaffd6d1a 100644 --- a/tools/testing/selftests/net/tun.c +++ b/tools/testing/selftests/net/tun.c @@ -356,6 +356,116 @@ static int ip_route_check(const char *intf, int famil= y, void *addr) return 0; } =20 +static int send_gso_udp_msg(int socket, struct sockaddr_storage *addr, + uint8_t *send_buf, int send_len, int gso_size) +{ + char control[CMSG_SPACE(sizeof(uint16_t))] =3D { 0 }; + int alen =3D sockaddr_len(addr->ss_family); + struct msghdr msg =3D { 0 }; + struct iovec iov =3D { 0 }; + int ret; + + iov.iov_base =3D send_buf; + iov.iov_len =3D send_len; + + msg.msg_iov =3D &iov; + msg.msg_iovlen =3D 1; + msg.msg_name =3D addr; + msg.msg_namelen =3D alen; + + if (gso_size > 0) { + struct cmsghdr *cmsg; + + msg.msg_control =3D control; + msg.msg_controllen =3D sizeof(control); + + cmsg =3D CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level =3D SOL_UDP; + cmsg->cmsg_type =3D UDP_SEGMENT; + cmsg->cmsg_len =3D CMSG_LEN(sizeof(uint16_t)); + *(uint16_t *)CMSG_DATA(cmsg) =3D gso_size; + } + + ret =3D sendmsg(socket, &msg, 0); + if (ret < 0) + perror("sendmsg"); + + return ret; +} + +static int validate_hdrlen(uint8_t **cur, int *len, int x) +{ + if (*len < x) + return -1; + *cur +=3D x; + *len -=3D x; + return 0; +} + +static int parse_udp_tunnel_vnet_packet(uint8_t *buf, int len, int tunnel_= type, + bool is_tap) +{ + struct ipv6hdr *iph6; + struct udphdr *udph; + struct iphdr *iph4; + uint8_t *cur =3D buf; + + if (validate_hdrlen(&cur, &len, TUN_VNET_TNL_SIZE)) + return -1; + + if (is_tap) { + if (validate_hdrlen(&cur, &len, ETH_HLEN)) + return -1; + } + + if (tunnel_type & UDP_TUNNEL_OUTER_IPV4) { + iph4 =3D (struct iphdr *)cur; + if (validate_hdrlen(&cur, &len, sizeof(struct iphdr))) + return -1; + if (iph4->version !=3D 4 || iph4->protocol !=3D IPPROTO_UDP) + return -1; + } else { + iph6 =3D (struct ipv6hdr *)cur; + if (validate_hdrlen(&cur, &len, sizeof(struct ipv6hdr))) + return -1; + if (iph6->version !=3D 6 || iph6->nexthdr !=3D IPPROTO_UDP) + return -1; + } + + udph =3D (struct udphdr *)cur; + if (validate_hdrlen(&cur, &len, sizeof(struct udphdr))) + return -1; + if (ntohs(udph->dest) !=3D VN_PORT) + return -1; + + if (validate_hdrlen(&cur, &len, 8)) + return -1; + if (validate_hdrlen(&cur, &len, ETH_HLEN)) + return -1; + + if (tunnel_type & UDP_TUNNEL_INNER_IPV4) { + iph4 =3D (struct iphdr *)cur; + if (validate_hdrlen(&cur, &len, sizeof(struct iphdr))) + return -1; + if (iph4->version !=3D 4 || iph4->protocol !=3D IPPROTO_UDP) + return -1; + } else { + iph6 =3D (struct ipv6hdr *)cur; + if (validate_hdrlen(&cur, &len, sizeof(struct ipv6hdr))) + return -1; + if (iph6->version !=3D 6 || iph6->nexthdr !=3D IPPROTO_UDP) + return -1; + } + + udph =3D (struct udphdr *)cur; + if (validate_hdrlen(&cur, &len, sizeof(struct udphdr))) + return -1; + if (ntohs(udph->dest) !=3D UDP_DST_PORT) + return -1; + + return len; +} + FIXTURE(tun) { char ifname[IFNAMSIZ]; @@ -683,6 +793,68 @@ receive_gso_packet_from_tunnel(FIXTURE_DATA(tun_vnet_u= dptnl) * self, return total_len; } =20 +static int send_gso_packet_into_tunnel(FIXTURE_DATA(tun_vnet_udptnl) * sel= f, + const FIXTURE_VARIANT(tun_vnet_udptnl) * + variant) +{ + int family =3D (variant->tunnel_type & UDP_TUNNEL_INNER_IPV4) ? AF_INET : + AF_INET6; + uint8_t buf[MAX_VNET_TUNNEL_PACKET_SZ] =3D { 0 }; + int payload_len =3D variant->data_size; + int gso_size =3D variant->gso_size; + struct sockaddr_storage ssa, dsa; + + assign_sockaddr_vars(family, 0, &ssa, &dsa); + return send_gso_udp_msg(self->sock, &dsa, buf, payload_len, gso_size); +} + +static int +receive_gso_packet_from_tun(FIXTURE_DATA(tun_vnet_udptnl) * self, + const FIXTURE_VARIANT(tun_vnet_udptnl) * variant, + struct virtio_net_hdr_v1_hash_tunnel *vnet_hdr) +{ + struct timeval timeout =3D { .tv_sec =3D TIMEOUT_SEC }; + uint8_t buf[MAX_VNET_TUNNEL_PACKET_SZ]; + int tunnel_type =3D variant->tunnel_type; + int payload_len =3D variant->data_size; + bool is_tap =3D variant->is_tap; + int ret, len, total_len =3D 0; + int tun_fd =3D self->fd; + fd_set fdset; + + while (total_len < payload_len) { + FD_ZERO(&fdset); + FD_SET(tun_fd, &fdset); + + ret =3D select(tun_fd + 1, &fdset, NULL, NULL, &timeout); + if (ret <=3D 0) { + perror("select"); + break; + } + if (!FD_ISSET(tun_fd, &fdset)) + continue; + + len =3D read(tun_fd, buf, sizeof(buf)); + if (len <=3D 0) { + if (len < 0 && errno !=3D EAGAIN && errno !=3D EWOULDBLOCK) + perror("read"); + break; + } + + len =3D parse_udp_tunnel_vnet_packet(buf, len, tunnel_type, + is_tap); + if (len < 0) + continue; + + if (total_len =3D=3D 0) + memcpy(vnet_hdr, buf, TUN_VNET_TNL_SIZE); + + total_len +=3D len; + } + + return total_len; +} + TEST_F(tun_vnet_udptnl, send_gso_packet) { uint8_t pkt[MAX_VNET_TUNNEL_PACKET_SZ]; @@ -699,4 +871,26 @@ TEST_F(tun_vnet_udptnl, send_gso_packet) ASSERT_EQ(r_num_mss, variant->r_num_mss); } =20 +TEST_F(tun_vnet_udptnl, recv_gso_packet) +{ + struct virtio_net_hdr_v1_hash_tunnel vnet_hdr =3D { 0 }; + struct virtio_net_hdr_v1 *vh =3D &vnet_hdr.hash_hdr.hdr; + int ret, gso_type =3D VIRTIO_NET_HDR_GSO_UDP_L4; + + ret =3D send_gso_packet_into_tunnel(self, variant); + ASSERT_EQ(ret, variant->data_size); + + memset(&vnet_hdr, 0, sizeof(vnet_hdr)); + ret =3D receive_gso_packet_from_tun(self, variant, &vnet_hdr); + ASSERT_EQ(ret, variant->data_size); + + if (!variant->no_gso) { + ASSERT_EQ(vh->gso_size, variant->gso_size); + gso_type |=3D (variant->tunnel_type & UDP_TUNNEL_OUTER_IPV4) ? + (VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV4) : + (VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV6); + ASSERT_EQ(vh->gso_type, gso_type); + } +} + TEST_HARNESS_MAIN --=20 2.49.0