From nobody Mon Sep 16 19:47:17 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1675222696; cv=none; d=zohomail.com; s=zohoarc; b=CM3tYBOkuWc5wk9g6TtIKJv1EiWoxKvy/USC2sUJ0zebe/hp3op4VdOKtC5NCRQ8LEHPhWW8q0wefmlA/eR0Zk+Zxd4OU588yeQHjtyxz87jGaRKYxoM30tjSZm3M7A0WnSWarStO1gIz8GtmHfbnnAnIo4tF7bo/oMRgFSPXGw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1675222696; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject; bh=jv/afEJcthyHIvIcMbqTIPEoZmHEVzJWfRny7dTpMv8=; b=MOrPA4baLX/w3gP2nelnyTj4IM1dmQeINDONwYELihC33+CBagVZhjnatcB4ukdyYi5zQE8nKI2Dy8RsBXFmDABFqLTN0jnkfkBx8A3JjJlJO+SzSI8+lj69ElkAhfUFdBcj8MxV67/T+yQJjQK/uCiHhaulgJz67b59CRamzwU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1675222696042259.2324314942499; Tue, 31 Jan 2023 19:38:16 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pN3vw-0008WP-SJ; Tue, 31 Jan 2023 22:37:16 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pN3vm-000849-8m for qemu-devel@nongnu.org; Tue, 31 Jan 2023 22:37:07 -0500 Received: from mail-pl1-x634.google.com ([2607:f8b0:4864:20::634]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pN3vk-0000SU-16 for qemu-devel@nongnu.org; Tue, 31 Jan 2023 22:37:06 -0500 Received: by mail-pl1-x634.google.com with SMTP id r8so10320948pls.2 for ; Tue, 31 Jan 2023 19:37:03 -0800 (PST) Received: from alarm.flets-east.jp ([2400:4050:a840:1e00:4457:c267:5e09:481b]) by smtp.gmail.com with ESMTPSA id x15-20020a170902ec8f00b001968b529c98sm4185557plg.128.2023.01.31.19.37.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Jan 2023 19:37:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=daynix-com.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=jv/afEJcthyHIvIcMbqTIPEoZmHEVzJWfRny7dTpMv8=; b=PnDSNIGN9euqV9THwePUCtKSTir2QKhhYdC+LvnQHOoRn8Vw2dPv4Gbp9Oe1vidazx e7JMnl4JWpNDrsU9b9Ovi3NfRuaPMBiN9t5vFl7gQT4wW8t+1WwB8Kuo5FpEWI7+fjuo f9J9t6hs1FmZgqHN7FjssedCgNn6F2YVP7oK+GxNOteL650Z/FVYztNWNm3/op+TdXpw U2yF1MCX9Zim6Fg36oIVj1pq5XUCw8YpJOEpj7y7e68hc/I1GZNzGN6vJgeYuJNbiXh8 tajn1+EuuSU3ytiuTHIIulRJUV8mUwqZ+rqXTDfXiXv6F1IlGt43IX2k4ql2u34RunCs 5cjQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=jv/afEJcthyHIvIcMbqTIPEoZmHEVzJWfRny7dTpMv8=; b=5eyV1xa+8vwQ77IRj55V5s0DQITLBAXLI9E8Y+yFMELQxwYMv7bgsDMQm3RZZnkr6k a5buDxaKm7l/R9tLukllzNdrBQ0gHjpDJEmtOSW+STnsjaKI2JEZlXAsn/5NNGFMw+TE 2iPE/pUbD4sXCtgZUUx2Je0q2/Rh6Gp6en3e7jQ6SmT5yDTfy5fXpVFHvBPDw42VXW30 V9XTn6rWyHYMVGsa0kFmTS57iR7N0cxX8Cg/G9f3s1Gc0UYCaF6eqZebJj2h52Ov3881 d7GEtdeS9bcHf/EVcobiqvoTdnC66mXDWmS/JQih2btFHBWij/7x8s1pG+F0W8UiC+kF Ming== X-Gm-Message-State: AO0yUKVI2IkRI+JD+/tztt0CZBdslopt+I0uIXTA8QVAmUIPYt4+amtr rnezaEL6SsdIMV+PSpY/WDrpSQ== X-Google-Smtp-Source: AK7set+RqRivFZqzSjjLIB6tczKBOyp/weSeFdOum7XJQQ0JLvrc/ylud0L7jEJKBvzSCz4643+ZTA== X-Received: by 2002:a17:903:2444:b0:195:f06f:84ff with SMTP id l4-20020a170903244400b00195f06f84ffmr1507153pls.50.1675222623280; Tue, 31 Jan 2023 19:37:03 -0800 (PST) From: Akihiko Odaki To: Cc: Jason Wang , Dmitry Fleytman , Thomas Huth , Laurent Vivier , Paolo Bonzini , qemu-devel@nongnu.org, qemu-ppc@nongnu.org, "Michael S . Tsirkin" , Yan Vugenfirer , Yuri Benditovich , Sriram Yagnaraman , Alexander Bulekov , Akihiko Odaki Subject: [PATCH v5 24/29] hw/net/net_tx_pkt: Implement TCP segmentation Date: Wed, 1 Feb 2023 12:35:34 +0900 Message-Id: <20230201033539.30049-25-akihiko.odaki@daynix.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230201033539.30049-1-akihiko.odaki@daynix.com> References: <20230201033539.30049-1-akihiko.odaki@daynix.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=2607:f8b0:4864:20::634; envelope-from=akihiko.odaki@daynix.com; helo=mail-pl1-x634.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer2=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @daynix-com.20210112.gappssmtp.com) X-ZM-MESSAGEID: 1675222696447100001 Content-Type: text/plain; charset="utf-8" There was no proper implementation of TCP segmentation before this change, and net_tx_pkt relied solely on IPv4 fragmentation. Not only this is not aligned with the specification, but it also resulted in corrupted IPv6 packets. This is particularly problematic for the igb, a new proposed device implementation; igb provides loopback feature for VMDq and the feature relies on software segmentation. Implement proper TCP segmentation in net_tx_pkt to fix such a scenario. Signed-off-by: Akihiko Odaki --- hw/net/net_tx_pkt.c | 248 ++++++++++++++++++++++++++++++++++++-------- include/net/eth.h | 5 - net/eth.c | 27 ----- 3 files changed, 206 insertions(+), 74 deletions(-) diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index 6afd3f6693..4a35e8429d 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -326,7 +326,8 @@ bool net_tx_pkt_build_vheader(struct NetTxPkt *pkt, boo= l tso_enable, case VIRTIO_NET_HDR_GSO_TCPV6: bytes_read =3D iov_to_buf(&pkt->vec[NET_TX_PKT_PL_START_FRAG], pkt->payload_frags, 0, &l4hdr, sizeof(l4hd= r)); - if (bytes_read < sizeof(l4hdr)) { + if (bytes_read < sizeof(l4hdr) || + l4hdr.th_off * sizeof(uint32_t) < sizeof(l4hdr)) { return false; } =20 @@ -466,15 +467,14 @@ void net_tx_pkt_reset(struct NetTxPkt *pkt) pkt->l4proto =3D 0; } =20 -static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt) +static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt, + struct iovec *iov, uint32_t iov_len, + uint16_t csl) { - struct iovec *iov =3D &pkt->vec[NET_TX_PKT_L2HDR_FRAG]; uint32_t csum_cntr; uint16_t csum =3D 0; uint32_t cso; /* num of iovec without vhdr */ - uint32_t iov_len =3D pkt->payload_frags + NET_TX_PKT_PL_START_FRAG - 1; - uint16_t csl; size_t csum_offset =3D pkt->virt_hdr.csum_start + pkt->virt_hdr.csum_o= ffset; uint16_t l3_proto =3D eth_get_l3_proto(iov, 1, iov->iov_len); =20 @@ -482,8 +482,6 @@ static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt) iov_from_buf(iov, iov_len, csum_offset, &csum, sizeof csum); =20 /* Calculate L4 TCP/UDP checksum */ - csl =3D pkt->payload_len; - csum_cntr =3D 0; cso =3D 0; /* add pseudo header to csum */ @@ -509,14 +507,13 @@ static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pk= t) #define NET_MAX_FRAG_SG_LIST (64) =20 static size_t net_tx_pkt_fetch_fragment(struct NetTxPkt *pkt, - int *src_idx, size_t *src_offset, struct iovec *dst, int *dst_idx) + int *src_idx, size_t *src_offset, size_t src_len, + struct iovec *dst, int *dst_idx) { size_t fetched =3D 0; struct iovec *src =3D pkt->vec; =20 - *dst_idx =3D NET_TX_PKT_PL_START_FRAG; - - while (fetched < IP_FRAG_ALIGN_SIZE(pkt->virt_hdr.gso_size)) { + while (fetched < src_len) { =20 /* no more place in fragment iov */ if (*dst_idx =3D=3D NET_MAX_FRAG_SG_LIST) { @@ -531,7 +528,7 @@ static size_t net_tx_pkt_fetch_fragment(struct NetTxPkt= *pkt, =20 dst[*dst_idx].iov_base =3D src[*src_idx].iov_base + *src_offset; dst[*dst_idx].iov_len =3D MIN(src[*src_idx].iov_len - *src_offset, - IP_FRAG_ALIGN_SIZE(pkt->virt_hdr.gso_size) - fetched); + src_len - fetched); =20 *src_offset +=3D dst[*dst_idx].iov_len; fetched +=3D dst[*dst_idx].iov_len; @@ -560,58 +557,223 @@ static void net_tx_pkt_sendv( } } =20 +static bool net_tx_pkt_tcp_fragment_init(struct NetTxPkt *pkt, + struct iovec *fragment, + int *pl_idx, + size_t *l4hdr_len, + int *src_idx, + size_t *src_offset, + size_t *src_len) +{ + struct iovec *l4 =3D fragment + NET_TX_PKT_PL_START_FRAG; + size_t bytes_read =3D 0; + struct tcp_hdr *th; + + if (!pkt->payload_frags) { + return false; + } + + l4->iov_len =3D pkt->virt_hdr.hdr_len - pkt->hdr_len; + l4->iov_base =3D g_malloc(l4->iov_len); + + *src_idx =3D NET_TX_PKT_PL_START_FRAG; + while (pkt->vec[*src_idx].iov_len < l4->iov_len - bytes_read) { + memcpy((char *)l4->iov_base + bytes_read, pkt->vec[*src_idx].iov_b= ase, + pkt->vec[*src_idx].iov_len); + + bytes_read +=3D pkt->vec[*src_idx].iov_len; + + (*src_idx)++; + if (*src_idx >=3D pkt->payload_frags + NET_TX_PKT_PL_START_FRAG) { + g_free(l4->iov_base); + return false; + } + } + + *src_offset =3D l4->iov_len - bytes_read; + memcpy((char *)l4->iov_base + bytes_read, pkt->vec[*src_idx].iov_base, + *src_offset); + + th =3D l4->iov_base; + th->th_flags &=3D ~(TH_FIN | TH_PUSH); + + *pl_idx =3D NET_TX_PKT_PL_START_FRAG + 1; + *l4hdr_len =3D l4->iov_len; + *src_len =3D pkt->virt_hdr.gso_size; + + return true; +} + +static void net_tx_pkt_tcp_fragment_deinit(struct iovec *fragment) +{ + g_free(fragment[NET_TX_PKT_PL_START_FRAG].iov_base); +} + +static void net_tx_pkt_tcp_fragment_fix(struct NetTxPkt *pkt, + struct iovec *fragment, + size_t fragment_len, + uint8_t gso_type) +{ + struct iovec *l3hdr =3D fragment + NET_TX_PKT_L3HDR_FRAG; + struct iovec *l4hdr =3D fragment + NET_TX_PKT_PL_START_FRAG; + struct ip_header *ip =3D l3hdr->iov_base; + struct ip6_header *ip6 =3D l3hdr->iov_base; + size_t len =3D l3hdr->iov_len + l4hdr->iov_len + fragment_len; + + switch (gso_type) { + case VIRTIO_NET_HDR_GSO_TCPV4: + ip->ip_len =3D cpu_to_be16(len); + eth_fix_ip4_checksum(l3hdr->iov_base, l3hdr->iov_len); + break; + + case VIRTIO_NET_HDR_GSO_TCPV6: + len -=3D sizeof(struct ip6_header); + ip6->ip6_ctlun.ip6_un1.ip6_un1_plen =3D cpu_to_be16(len); + break; + } +} + +static void net_tx_pkt_tcp_fragment_advance(struct NetTxPkt *pkt, + struct iovec *fragment, + size_t fragment_len, + uint8_t gso_type) +{ + struct iovec *l3hdr =3D fragment + NET_TX_PKT_L3HDR_FRAG; + struct iovec *l4hdr =3D fragment + NET_TX_PKT_PL_START_FRAG; + struct ip_header *ip =3D l3hdr->iov_base; + struct tcp_hdr *th =3D l4hdr->iov_base; + + if (gso_type =3D=3D VIRTIO_NET_HDR_GSO_TCPV4) { + ip->ip_id =3D cpu_to_be16(be16_to_cpu(ip->ip_id) + 1); + } + + th->th_seq =3D cpu_to_be32(be32_to_cpu(th->th_seq) + fragment_len); + th->th_flags &=3D ~TH_CWR; +} + +static void net_tx_pkt_udp_fragment_init(struct NetTxPkt *pkt, + int *pl_idx, + size_t *l4hdr_len, + int *src_idx, size_t *src_offset, + size_t *src_len) +{ + *pl_idx =3D NET_TX_PKT_PL_START_FRAG; + *l4hdr_len =3D 0; + *src_idx =3D NET_TX_PKT_PL_START_FRAG; + *src_offset =3D 0; + *src_len =3D IP_FRAG_ALIGN_SIZE(pkt->virt_hdr.gso_size); +} + +static void net_tx_pkt_udp_fragment_fix(struct NetTxPkt *pkt, + struct iovec *fragment, + size_t fragment_offset, + size_t fragment_len) +{ + bool more_frags =3D fragment_offset + fragment_len < pkt->payload_len; + uint16_t orig_flags; + struct iovec *l3hdr =3D fragment + NET_TX_PKT_L3HDR_FRAG; + struct ip_header *ip =3D l3hdr->iov_base; + uint16_t frag_off_units =3D fragment_offset / IP_FRAG_UNIT_SIZE; + uint16_t new_ip_off; + + assert(fragment_offset % IP_FRAG_UNIT_SIZE =3D=3D 0); + assert((frag_off_units & ~IP_OFFMASK) =3D=3D 0); + + orig_flags =3D be16_to_cpu(ip->ip_off) & ~(IP_OFFMASK | IP_MF); + new_ip_off =3D frag_off_units | orig_flags | (more_frags ? IP_MF : 0); + ip->ip_off =3D cpu_to_be16(new_ip_off); + ip->ip_len =3D cpu_to_be16(l3hdr->iov_len + fragment_len); + + eth_fix_ip4_checksum(l3hdr->iov_base, l3hdr->iov_len); +} + static bool net_tx_pkt_do_sw_fragmentation(struct NetTxPkt *pkt, NetTxPktCallback callback, void *context) { + uint8_t gso_type =3D pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN; + struct iovec fragment[NET_MAX_FRAG_SG_LIST]; - size_t fragment_len =3D 0; - bool more_frags =3D false; - - /* some pointers for shorter code */ - void *l2_iov_base, *l3_iov_base; - size_t l2_iov_len, l3_iov_len; - int src_idx =3D NET_TX_PKT_PL_START_FRAG, dst_idx; - size_t src_offset =3D 0; + size_t fragment_len; + size_t l4hdr_len; + size_t src_len; + + int src_idx, dst_idx, pl_idx; + size_t src_offset; size_t fragment_offset =3D 0; struct virtio_net_hdr virt_hdr =3D { .flags =3D pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM ? VIRTIO_NET_HDR_F_DATA_VALID : 0 }; =20 - l2_iov_base =3D pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_base; - l2_iov_len =3D pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len; - l3_iov_base =3D pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_base; - l3_iov_len =3D pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len; - /* Copy headers */ fragment[NET_TX_PKT_VHDR_FRAG].iov_base =3D &virt_hdr; fragment[NET_TX_PKT_VHDR_FRAG].iov_len =3D sizeof(virt_hdr); - fragment[NET_TX_PKT_L2HDR_FRAG].iov_base =3D l2_iov_base; - fragment[NET_TX_PKT_L2HDR_FRAG].iov_len =3D l2_iov_len; - fragment[NET_TX_PKT_L3HDR_FRAG].iov_base =3D l3_iov_base; - fragment[NET_TX_PKT_L3HDR_FRAG].iov_len =3D l3_iov_len; + fragment[NET_TX_PKT_L2HDR_FRAG] =3D pkt->vec[NET_TX_PKT_L2HDR_FRAG]; + fragment[NET_TX_PKT_L3HDR_FRAG] =3D pkt->vec[NET_TX_PKT_L3HDR_FRAG]; =20 + switch (gso_type) { + case VIRTIO_NET_HDR_GSO_TCPV4: + case VIRTIO_NET_HDR_GSO_TCPV6: + if (!net_tx_pkt_tcp_fragment_init(pkt, fragment, &pl_idx, &l4hdr_l= en, + &src_idx, &src_offset, &src_len)= ) { + return false; + } + break; =20 - /* Put as much data as possible and send */ - do { - fragment_len =3D net_tx_pkt_fetch_fragment(pkt, &src_idx, &src_off= set, - fragment, &dst_idx); + case VIRTIO_NET_HDR_GSO_UDP: + net_tx_pkt_do_sw_csum(pkt, &pkt->vec[NET_TX_PKT_L2HDR_FRAG], + pkt->payload_frags + NET_TX_PKT_PL_START_FRA= G - 1, + pkt->payload_len); + net_tx_pkt_udp_fragment_init(pkt, &pl_idx, &l4hdr_len, + &src_idx, &src_offset, &src_len); + break; =20 - more_frags =3D (fragment_offset + fragment_len < pkt->payload_len); + default: + abort(); + } =20 - eth_setup_ip4_fragmentation(l2_iov_base, l2_iov_len, l3_iov_base, - l3_iov_len, fragment_len, fragment_offset, more_frags); + /* Put as much data as possible and send */ + while (true) { + dst_idx =3D pl_idx; + fragment_len =3D net_tx_pkt_fetch_fragment(pkt, + &src_idx, &src_offset, src_len, fragment, &dst_idx); + if (!fragment_len) { + break; + } =20 - eth_fix_ip4_checksum(l3_iov_base, l3_iov_len); + switch (gso_type) { + case VIRTIO_NET_HDR_GSO_TCPV4: + case VIRTIO_NET_HDR_GSO_TCPV6: + net_tx_pkt_tcp_fragment_fix(pkt, fragment, fragment_len, gso_t= ype); + net_tx_pkt_do_sw_csum(pkt, fragment + NET_TX_PKT_L2HDR_FRAG, + dst_idx - NET_TX_PKT_L2HDR_FRAG, + l4hdr_len + fragment_len); + break; + + case VIRTIO_NET_HDR_GSO_UDP: + net_tx_pkt_udp_fragment_fix(pkt, fragment, fragment_offset, + fragment_len); + break; + } =20 callback(context, fragment + NET_TX_PKT_L2HDR_FRAG, dst_idx - NET_TX_PKT_L2= HDR_FRAG, fragment + NET_TX_PKT_VHDR_FRAG, dst_idx - NET_TX_PKT_VHD= R_FRAG); =20 + if (gso_type =3D=3D VIRTIO_NET_HDR_GSO_TCPV4 || + gso_type =3D=3D VIRTIO_NET_HDR_GSO_TCPV6) { + net_tx_pkt_tcp_fragment_advance(pkt, fragment, fragment_len, + gso_type); + } + fragment_offset +=3D fragment_len; + } =20 - } while (fragment_len && more_frags); + if (gso_type =3D=3D VIRTIO_NET_HDR_GSO_TCPV4 || + gso_type =3D=3D VIRTIO_NET_HDR_GSO_TCPV6) { + net_tx_pkt_tcp_fragment_deinit(fragment); + } =20 return true; } @@ -627,10 +789,6 @@ bool net_tx_pkt_send_custom(struct NetTxPkt *pkt, bool= offload, { assert(pkt); =20 - if (!offload && pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { - net_tx_pkt_do_sw_csum(pkt); - } - /* * Since underlying infrastructure does not support IP datagrams longer * than 64K we should drop such packets and don't even try to send @@ -644,6 +802,12 @@ bool net_tx_pkt_send_custom(struct NetTxPkt *pkt, bool= offload, } =20 if (offload || pkt->virt_hdr.gso_type =3D=3D VIRTIO_NET_HDR_GSO_NONE) { + if (!offload && pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)= { + net_tx_pkt_do_sw_csum(pkt, &pkt->vec[NET_TX_PKT_L2HDR_FRAG], + pkt->payload_frags + NET_TX_PKT_PL_START= _FRAG - 1, + pkt->payload_len); + } + net_tx_pkt_fix_ip6_payload_len(pkt); callback(context, pkt->vec + NET_TX_PKT_L2HDR_FRAG, pkt->payload_frags + NET_TX_PKT_PL_START_FRAG - NET_TX_PK= T_L2HDR_FRAG, diff --git a/include/net/eth.h b/include/net/eth.h index 6e699b0d7a..2b4374fae4 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -400,11 +400,6 @@ void eth_get_protocols(const struct iovec *iov, int io= vcnt, eth_ip4_hdr_info *ip4hdr_info, eth_l4_hdr_info *l4hdr_info); =20 -void eth_setup_ip4_fragmentation(const void *l2hdr, size_t l2hdr_len, - void *l3hdr, size_t l3hdr_len, - size_t l3payload_len, - size_t frag_offset, bool more_frags); - void eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len); =20 diff --git a/net/eth.c b/net/eth.c index f074b2f9f3..36d39b4357 100644 --- a/net/eth.c +++ b/net/eth.c @@ -314,33 +314,6 @@ eth_strip_vlan_ex(const struct iovec *iov, int iovcnt,= size_t iovoff, return 0; } =20 -void -eth_setup_ip4_fragmentation(const void *l2hdr, size_t l2hdr_len, - void *l3hdr, size_t l3hdr_len, - size_t l3payload_len, - size_t frag_offset, bool more_frags) -{ - const struct iovec l2vec =3D { - .iov_base =3D (void *) l2hdr, - .iov_len =3D l2hdr_len - }; - - if (eth_get_l3_proto(&l2vec, 1, l2hdr_len) =3D=3D ETH_P_IP) { - uint16_t orig_flags; - struct ip_header *iphdr =3D (struct ip_header *) l3hdr; - uint16_t frag_off_units =3D frag_offset / IP_FRAG_UNIT_SIZE; - uint16_t new_ip_off; - - assert(frag_offset % IP_FRAG_UNIT_SIZE =3D=3D 0); - assert((frag_off_units & ~IP_OFFMASK) =3D=3D 0); - - orig_flags =3D be16_to_cpu(iphdr->ip_off) & ~(IP_OFFMASK|IP_MF); - new_ip_off =3D frag_off_units | orig_flags | (more_frags ? IP_MF = : 0); - iphdr->ip_off =3D cpu_to_be16(new_ip_off); - iphdr->ip_len =3D cpu_to_be16(l3payload_len + l3hdr_len); - } -} - void eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len) { --=20 2.39.1