From nobody Fri Jan 9 18:25:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 951CF3161A6 for ; Tue, 6 Jan 2026 01:36:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767663365; cv=none; b=qQ0b40bafZ7vetBY6gNKrqvEeJU6Mv5SSY0FdizNdOv+Hq/K9T60vZ3gEDS9ezAIV1txMrgE5cgLa9GBu/VE7mFOFQgMopYljnhpxByuLgT0XVorbeNh1oi5Hf5Eg4xNkgoLawgae7gP4izCXDmSN3Z1LjzOadLDLsos4AOTpas= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767663365; c=relaxed/simple; bh=1Q1RiDIAFkCQpUf2Av+niR0MOVEyfWEtRaYvKQV0ctY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=o6BDXyDtc3VTxuVbE1OJ5J867HTjD2PkNH2nxE4gQ+GxyJ5JZ+f3VfBFqHIL4SLVjAH8vHStxc7kWtnRXF0FgW0PJFfj3e2CRTy/cULCjhsia0n4ZVEiMWU35IH1UzhlDQeOXrNdLbGZBLDXFb9A8umXaJXZc21PxA7iqtg9uu4= 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=LO52RI6T; arc=none smtp.client-ip=170.10.133.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="LO52RI6T" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1767663361; 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=oVLA9fiklNQD9VQBuHy22IKHtUeJIXv5AwA+1ApaiNA=; b=LO52RI6Td3gLkpby2V/0IZE9dun01gXG9cjBX4LDpemdjl4eNA16tTaErJH9N6HhGCtd1t kcKd44jmMfn0s3ki4iWAlbjMqTXnU/11mwDp4CN72ZtZHIuuu7LVMcunfNRH3XoZXgqCik RuE2+I5B3AuS/JseEJoKqWDJROj3+90= 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-520-S3W0UybXMLuXhJ4K6z1OrQ-1; Mon, 05 Jan 2026 20:35:58 -0500 X-MC-Unique: S3W0UybXMLuXhJ4K6z1OrQ-1 X-Mimecast-MFC-AGG-ID: S3W0UybXMLuXhJ4K6z1OrQ_1767663357 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 EC554195DE48; Tue, 6 Jan 2026 01:35:56 +0000 (UTC) Received: from xudu-thinkpadx1carbongen9.nay.csb (unknown [10.66.60.72]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1555E180044F; Tue, 6 Jan 2026 01:35:52 +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 v4 6/8] selftest: tun: Add test for sending gso packet into tun Date: Tue, 6 Jan 2026 09:35:19 +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.111 Content-Type: text/plain; charset="utf-8" The test constructs a raw packet, prepends a virtio_net_hdr, and writes the result to the TUN device. This mimics the behavior of a vm forwarding a guest's packet to the host networking stack. Signed-off-by: Xu Du --- v3 -> v4: - Expand the buffer to accommodate the maximum length of test packets. v1 -> v2: - Correct spelling of 'recieve' to 'receive'. - Avoid busy waiting caused by recv() returning empty. tools/testing/selftests/net/tun.c | 151 ++++++++++++++++++++++++++++-- 1 file changed, 142 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/net/tun.c b/tools/testing/selftests/ne= t/tun.c index add5e91df6c9..ececc5ed4909 100644 --- a/tools/testing/selftests/net/tun.c +++ b/tools/testing/selftests/net/tun.c @@ -75,8 +75,35 @@ static struct in6_addr param_ipaddr6_inner_src =3D { #define UDP_TUNNEL_OUTER_IPV4 (UDP_TUNNEL_VXLAN_4IN4 | UDP_TUNNEL_VXLAN_6I= N4) #define UDP_TUNNEL_INNER_IPV4 (UDP_TUNNEL_VXLAN_4IN4 | UDP_TUNNEL_VXLAN_4I= N6) =20 +#define UDP_TUNNEL_VXLAN_4IN4_HDRLEN \ + (ETH_HLEN + 2 * sizeof(struct iphdr) + 8 + 2 * sizeof(struct udphdr)) +#define UDP_TUNNEL_VXLAN_6IN6_HDRLEN \ + (ETH_HLEN + 2 * sizeof(struct ipv6hdr) + 8 + 2 * sizeof(struct udphdr)) +#define UDP_TUNNEL_VXLAN_4IN6_HDRLEN \ + (ETH_HLEN + sizeof(struct iphdr) + sizeof(struct ipv6hdr) + 8 + \ + 2 * sizeof(struct udphdr)) +#define UDP_TUNNEL_VXLAN_6IN4_HDRLEN \ + (ETH_HLEN + sizeof(struct ipv6hdr) + sizeof(struct iphdr) + 8 + \ + 2 * sizeof(struct udphdr)) + +#define UDP_TUNNEL_HDRLEN(type) \ + ((type) =3D=3D UDP_TUNNEL_VXLAN_4IN4 ? UDP_TUNNEL_VXLAN_4IN4_HDRLEN : \ + (type) =3D=3D UDP_TUNNEL_VXLAN_6IN4 ? UDP_TUNNEL_VXLAN_6IN4_HDRLEN : \ + (type) =3D=3D UDP_TUNNEL_VXLAN_4IN6 ? UDP_TUNNEL_VXLAN_4IN6_HDRLEN : \ + (type) =3D=3D UDP_TUNNEL_VXLAN_6IN6 ? UDP_TUNNEL_VXLAN_6IN6_HDRLEN : \ + 0) + +#define UDP_TUNNEL_MSS(type) (ETH_DATA_LEN - UDP_TUNNEL_HDRLEN(type)) + +#define UDP_TUNNEL_MAX(type, is_tap) \ + (ETH_MAX_MTU - UDP_TUNNEL_HDRLEN(type) - ((is_tap) ? ETH_HLEN : 0)) + #define TUN_VNET_TNL_SIZE sizeof(struct virtio_net_hdr_v1_hash_tunnel) =20 +#define MAX_VNET_TUNNEL_PACKET_SZ \ + (TUN_VNET_TNL_SIZE + ETH_HLEN + UDP_TUNNEL_VXLAN_6IN6_HDRLEN + \ + ETH_MAX_MTU) + struct vxlan_setup_config { struct sockaddr_storage local_ip; struct sockaddr_storage remote_ip; @@ -402,15 +429,23 @@ FIXTURE(tun_vnet_udptnl) FIXTURE_VARIANT(tun_vnet_udptnl) { int tunnel_type; - bool is_tap; + int gso_size; + int data_size; + int r_num_mss; + bool is_tap, no_gso; }; =20 /* clang-format off */ #define TUN_VNET_UDPTNL_VARIANT_ADD(type, desc) = \ - FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##udptnl) { \ + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_1mss) { \ + /* send a single MSS: fall back to no GSO */ \ .tunnel_type =3D type, \ + .gso_size =3D UDP_TUNNEL_MSS(type), \ + .data_size =3D UDP_TUNNEL_MSS(type), \ + .r_num_mss =3D 1, \ .is_tap =3D true, \ - } + .no_gso =3D true, \ + }; /* clang-format on */ =20 TUN_VNET_UDPTNL_VARIANT_ADD(UDP_TUNNEL_VXLAN_4IN4, 4in4); @@ -558,14 +593,112 @@ FIXTURE_TEARDOWN(tun_vnet_udptnl) EXPECT_EQ(ret, 0); } =20 -TEST_F(tun_vnet_udptnl, basic) +static int build_gso_packet_into_tun(const FIXTURE_VARIANT(tun_vnet_udptnl= ) * + variant, + uint8_t *buf) { - int ret; - char cmd[256] =3D { 0 }; + int tunnel_type =3D variant->tunnel_type; + int payload_len =3D variant->data_size; + int gso_size =3D variant->gso_size; + int inner_family, outer_family; + bool is_tap =3D variant->is_tap; + uint8_t *outer_udph =3D NULL; + uint8_t *cur =3D buf; + int len, proto; + + len =3D (is_tap ? ETH_HLEN : 0) + UDP_TUNNEL_HDRLEN(tunnel_type); + inner_family =3D (tunnel_type & UDP_TUNNEL_INNER_IPV4) ? AF_INET : + AF_INET6; + outer_family =3D (tunnel_type & UDP_TUNNEL_OUTER_IPV4) ? AF_INET : + AF_INET6; + + cur +=3D build_virtio_net_hdr_v1_hash_tunnel(cur, is_tap, len, gso_size, + outer_family, inner_family); + + if (is_tap) { + proto =3D outer_family =3D=3D AF_INET ? ETH_P_IP : ETH_P_IPV6; + cur +=3D build_eth(cur, proto, param_hwaddr_outer_dst, + param_hwaddr_outer_src); + len -=3D ETH_HLEN; + } =20 - sprintf(cmd, "ip addr show %s > /dev/null 2>&1", param_dev_vxlan_name); - ret =3D system(cmd); - ASSERT_EQ(ret, 0); + if (outer_family =3D=3D AF_INET) { + len =3D len - sizeof(struct iphdr) + payload_len; + cur +=3D build_ipv4_header(cur, IPPROTO_UDP, len, + ¶m_ipaddr4_outer_dst, + ¶m_ipaddr4_outer_src); + } else { + len =3D len - sizeof(struct ipv6hdr) + payload_len; + cur +=3D build_ipv6_header(cur, IPPROTO_UDP, 0, len, + ¶m_ipaddr6_outer_dst, + ¶m_ipaddr6_outer_src); + } + + outer_udph =3D cur; + len -=3D sizeof(struct udphdr); + proto =3D inner_family =3D=3D AF_INET ? ETH_P_IP : ETH_P_IPV6; + cur +=3D build_udp_header(cur, UDP_SRC_PORT, VN_PORT, len); + cur +=3D build_vxlan_header(cur, VN_ID); + cur +=3D build_eth(cur, proto, param_hwaddr_inner_dst, + param_hwaddr_inner_src); + + len =3D sizeof(struct udphdr) + payload_len; + if (inner_family =3D=3D AF_INET) { + cur +=3D build_ipv4_header(cur, IPPROTO_UDP, len, + ¶m_ipaddr4_inner_dst, + ¶m_ipaddr4_inner_src); + } else { + cur +=3D build_ipv6_header(cur, IPPROTO_UDP, 0, len, + ¶m_ipaddr6_inner_dst, + ¶m_ipaddr6_inner_src); + } + + cur +=3D build_udp_packet(cur, UDP_DST_PORT, UDP_SRC_PORT, payload_len, + inner_family, false); + + build_udp_packet_csum(outer_udph, outer_family, false); + + return cur - buf; +} + +static int +receive_gso_packet_from_tunnel(FIXTURE_DATA(tun_vnet_udptnl) * self, + const FIXTURE_VARIANT(tun_vnet_udptnl) * variant, + int *r_num_mss) +{ + uint8_t packet_buf[MAX_VNET_TUNNEL_PACKET_SZ]; + int len, total_len =3D 0, socket =3D self->sock; + int payload_len =3D variant->data_size; + + while (total_len < payload_len) { + len =3D recv(socket, packet_buf, sizeof(packet_buf), 0); + if (len <=3D 0) { + if (len < 0 && errno !=3D EAGAIN && errno !=3D EWOULDBLOCK) + perror("recv"); + break; + } + + (*r_num_mss)++; + total_len +=3D len; + } + + return total_len; +} + +TEST_F(tun_vnet_udptnl, send_gso_packet) +{ + uint8_t pkt[MAX_VNET_TUNNEL_PACKET_SZ]; + int r_num_mss =3D 0; + int ret, off; + + memset(pkt, 0, sizeof(pkt)); + off =3D build_gso_packet_into_tun(variant, pkt); + ret =3D write(self->fd, pkt, off); + ASSERT_EQ(ret, off); + + ret =3D receive_gso_packet_from_tunnel(self, variant, &r_num_mss); + ASSERT_EQ(ret, variant->data_size); + ASSERT_EQ(r_num_mss, variant->r_num_mss); } =20 TEST_HARNESS_MAIN --=20 2.49.0