From patchwork Tue Jun 3 09:46:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Marchand X-Patchwork-Id: 2093380 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=P4bSbhcr; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4bBQqm1qVPz1yZ5 for ; Tue, 3 Jun 2025 19:47:48 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 017024185B; Tue, 3 Jun 2025 09:48:01 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id bXmrolIqY1qK; Tue, 3 Jun 2025 09:47:58 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org B1F13411F1 Authentication-Results: smtp2.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=P4bSbhcr Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id B1F13411F1; Tue, 3 Jun 2025 09:47:58 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 9C1EEC003A; Tue, 3 Jun 2025 09:47:58 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0D3D1C007B for ; Tue, 3 Jun 2025 09:47:57 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 9800261625 for ; Tue, 3 Jun 2025 09:47:24 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id Xx6zH4r3ycRR for ; Tue, 3 Jun 2025 09:47:23 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=david.marchand@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org 8B20A61670 Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 8B20A61670 Authentication-Results: smtp3.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=P4bSbhcr Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp3.osuosl.org (Postfix) with ESMTPS id 8B20A61670 for ; Tue, 3 Jun 2025 09:47:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1748944042; 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: in-reply-to:in-reply-to:references:references; bh=twcuhnqeuPNsAmt2Q/5VDCc0aZjslCT59ZPUrVFp48U=; b=P4bSbhcrF0oQNrV958n2SzslG+BaFP2nCwnNsfVsa5gqucefQu0WtPB65uVIV5bBfeTBjw wzEEei2vHza9XDBr5rtZviuGpowcbicbozmiMG2FZVaReL3E/jg0jT01ALoeDfJGO3blQE 72243kgjM/JAG8Yg5y21ujcZoafapzk= 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-494-H6MgBsxNMBih9-DajiqBww-1; Tue, 03 Jun 2025 05:47:21 -0400 X-MC-Unique: H6MgBsxNMBih9-DajiqBww-1 X-Mimecast-MFC-AGG-ID: H6MgBsxNMBih9-DajiqBww_1748944040 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 8F19B1955E7A; Tue, 3 Jun 2025 09:47:20 +0000 (UTC) Received: from dmarchan.lan (unknown [10.45.224.6]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 0443519560B5; Tue, 3 Jun 2025 09:47:18 +0000 (UTC) To: dev@openvswitch.org Date: Tue, 3 Jun 2025 11:46:33 +0200 Message-ID: <20250603094637.1250238-9-david.marchand@redhat.com> In-Reply-To: <20250603094637.1250238-1-david.marchand@redhat.com> References: <20250603094637.1250238-1-david.marchand@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: cedjDFJD9f57PFjMKkaplPW2Kk1tBTBNqVHpA59R_Pg_1748944040 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v5 08/12] dp-packet: Resolve unknown checksums. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: David Marchand via dev From: David Marchand Reply-To: David Marchand Cc: i.maximets@ovn.org Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Now that IP and L4 checksum offloading don't require tweaking Tx flags, update checksum status in parts of OVS that validate checksums (in case of unknown status). Signed-off-by: David Marchand --- lib/conntrack.c | 107 ++++++++++++++++++++++++---------------- lib/ipf.c | 7 ++- lib/netdev-native-tnl.c | 14 +++++- 3 files changed, 82 insertions(+), 46 deletions(-) diff --git a/lib/conntrack.c b/lib/conntrack.c index a17be27be2..fa09eb9f7e 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -125,8 +125,8 @@ reverse_icmp_type(uint8_t type); static uint8_t reverse_icmp6_type(uint8_t type); static inline bool -extract_l3_ipv4(struct conn_key *key, const void *data, size_t size, - const char **new_data, bool validate_checksum); +extract_l3_ipv4(struct dp_packet *pkt, struct conn_key *key, const void *data, + size_t size, const char **new_data); static inline bool extract_l3_ipv6(struct conn_key *key, const void *data, size_t size, const char **new_data); @@ -924,8 +924,8 @@ nat_inner_packet(struct dp_packet *pkt, struct conn_key *key, * 'extract_l4_icmp()'/'extract_l4_icmp6()'. */ if (key->dl_type == htons(ETH_TYPE_IP)) { inner_l3 = (char *) l4 + sizeof(struct icmp_header); - extract_l3_ipv4(&inner_key, inner_l3, tail - ((char *) inner_l3) - pad, - &inner_l4, false); + extract_l3_ipv4(NULL, &inner_key, inner_l3, + tail - ((char *) inner_l3) - pad, &inner_l4); } else { inner_l3 = (char *) l4 + sizeof(struct icmp6_data_header); extract_l3_ipv6(&inner_key, inner_l3, tail - ((char *) inner_l3) - pad, @@ -1688,8 +1688,8 @@ clean_thread_main(void *f_) * used to store a pointer to the first byte after the L3 header. 'Size' is * the size of the packet beyond the data pointer. */ static inline bool -extract_l3_ipv4(struct conn_key *key, const void *data, size_t size, - const char **new_data, bool validate_checksum) +extract_l3_ipv4(struct dp_packet *pkt, struct conn_key *key, const void *data, + size_t size, const char **new_data) { if (OVS_UNLIKELY(size < IP_HEADER_LEN)) { return false; @@ -1710,12 +1710,14 @@ extract_l3_ipv4(struct conn_key *key, const void *data, size_t size, return false; } - if (validate_checksum) { + if (pkt && dp_packet_ip_checksum_unknown(pkt)) { COVERAGE_INC(conntrack_l3csum_checked); if (csum(data, ip_len)) { COVERAGE_INC(conntrack_l3csum_err); + dp_packet_ip_checksum_set_bad(pkt); return false; } + dp_packet_ip_checksum_set_good(pkt); } if (new_data) { @@ -1811,8 +1813,8 @@ sctp_checksum_valid(const void *data, size_t size) } static inline bool -check_l4_tcp(const struct conn_key *key, const void *data, size_t size, - const void *l3, bool validate_checksum) +check_l4_tcp(struct dp_packet *pkt, const struct conn_key *key, + const void *data, size_t size, const void *l3) { const struct tcp_header *tcp = data; if (size < sizeof *tcp) { @@ -1824,12 +1826,20 @@ check_l4_tcp(const struct conn_key *key, const void *data, size_t size, return false; } - return validate_checksum ? checksum_valid(key, data, size, l3) : true; + if (pkt && dp_packet_l4_checksum_unknown(pkt)) { + if (!checksum_valid(key, data, size, l3)) { + dp_packet_l4_checksum_set_bad(pkt); + return false; + } + dp_packet_l4_checksum_set_good(pkt); + dp_packet_l4_proto_set_tcp(pkt); + } + return true; } static inline bool -check_l4_udp(const struct conn_key *key, const void *data, size_t size, - const void *l3, bool validate_checksum) +check_l4_udp(struct dp_packet *pkt, const struct conn_key *key, + const void *data, size_t size, const void *l3) { const struct udp_header *udp = data; if (size < sizeof *udp) { @@ -1842,8 +1852,16 @@ check_l4_udp(const struct conn_key *key, const void *data, size_t size, } /* Validation must be skipped if checksum is 0 on IPv4 packets */ - return (udp->udp_csum == 0 && key->dl_type == htons(ETH_TYPE_IP)) - || (validate_checksum ? checksum_valid(key, data, size, l3) : true); + if (!(udp->udp_csum == 0 && key->dl_type == htons(ETH_TYPE_IP)) + && (pkt && dp_packet_l4_checksum_unknown(pkt))) { + if (!checksum_valid(key, data, size, l3)) { + dp_packet_l4_checksum_set_bad(pkt); + return false; + } + dp_packet_l4_checksum_set_good(pkt); + dp_packet_l4_proto_set_udp(pkt); + } + return true; } static inline bool @@ -1878,19 +1896,27 @@ sctp_check_len(const struct sctp_header *sh, size_t size) } static inline bool -check_l4_sctp(const void *data, size_t size, bool validate_checksum) +check_l4_sctp(struct dp_packet *pkt, const void *data, size_t size) { if (OVS_UNLIKELY(!sctp_check_len(data, size))) { return false; } - return validate_checksum ? sctp_checksum_valid(data, size) : true; + if (pkt && dp_packet_l4_checksum_unknown(pkt)) { + if (!sctp_checksum_valid(data, size)) { + dp_packet_l4_checksum_set_bad(pkt); + return false; + } + dp_packet_l4_checksum_set_good(pkt); + dp_packet_l4_proto_set_sctp(pkt); + } + return true; } static inline bool -check_l4_icmp(const void *data, size_t size, bool validate_checksum) +check_l4_icmp(struct dp_packet *pkt, const void *data, size_t size) { - if (validate_checksum) { + if (pkt) { COVERAGE_INC(conntrack_l4csum_checked); if (csum(data, size)) { COVERAGE_INC(conntrack_l4csum_err); @@ -1902,10 +1928,10 @@ check_l4_icmp(const void *data, size_t size, bool validate_checksum) } static inline bool -check_l4_icmp6(const struct conn_key *key, const void *data, size_t size, - const void *l3, bool validate_checksum) +check_l4_icmp6(struct dp_packet *pkt, const struct conn_key *key, + const void *data, size_t size, const void *l3) { - return validate_checksum ? checksum_valid(key, data, size, l3) : true; + return pkt ? checksum_valid(key, data, size, l3) : true; } static inline bool @@ -1955,9 +1981,9 @@ extract_l4_sctp(struct conn_key *key, const void *data, size_t size, return key->src.port && key->dst.port; } -static inline bool extract_l4(struct conn_key *key, const void *data, - size_t size, bool *related, const void *l3, - bool validate_checksum, size_t *chk_len); +static inline bool extract_l4(struct dp_packet *pkt, struct conn_key *key, + const void *data, size_t size, bool *related, + const void *l3, size_t *chk_len); static uint8_t reverse_icmp_type(uint8_t type) @@ -2030,7 +2056,7 @@ extract_l4_icmp(struct conn_key *key, const void *data, size_t size, memset(&inner_key, 0, sizeof inner_key); inner_key.dl_type = htons(ETH_TYPE_IP); - bool ok = extract_l3_ipv4(&inner_key, l3, tail - l3, &l4, false); + bool ok = extract_l3_ipv4(NULL, &inner_key, l3, tail - l3, &l4); if (!ok) { return false; } @@ -2044,7 +2070,7 @@ extract_l4_icmp(struct conn_key *key, const void *data, size_t size, key->nw_proto = inner_key.nw_proto; size_t check_len = ICMP_ERROR_DATA_L4_LEN; - ok = extract_l4(key, l4, tail - l4, NULL, l3, false, &check_len); + ok = extract_l4(NULL, key, l4, tail - l4, NULL, l3, &check_len); if (ok) { conn_key_reverse(key); *related = true; @@ -2131,7 +2157,7 @@ extract_l4_icmp6(struct conn_key *key, const void *data, size_t size, key->dst = inner_key.dst; key->nw_proto = inner_key.nw_proto; - ok = extract_l4(key, l4, tail - l4, NULL, l3, false, NULL); + ok = extract_l4(NULL, key, l4, tail - l4, NULL, l3, NULL); if (ok) { conn_key_reverse(key); *related = true; @@ -2159,28 +2185,25 @@ extract_l4_icmp6(struct conn_key *key, const void *data, size_t size, * in an ICMP error. In this case, we skip the checksum and some length * validations. */ static inline bool -extract_l4(struct conn_key *key, const void *data, size_t size, bool *related, - const void *l3, bool validate_checksum, size_t *chk_len) +extract_l4(struct dp_packet *pkt, struct conn_key *key, const void *data, + size_t size, bool *related, const void *l3, size_t *chk_len) { if (key->nw_proto == IPPROTO_TCP) { - return (!related || check_l4_tcp(key, data, size, l3, - validate_checksum)) + return (!related || check_l4_tcp(pkt, key, data, size, l3)) && extract_l4_tcp(key, data, size, chk_len); } else if (key->nw_proto == IPPROTO_UDP) { - return (!related || check_l4_udp(key, data, size, l3, - validate_checksum)) + return (!related || check_l4_udp(pkt, key, data, size, l3)) && extract_l4_udp(key, data, size, chk_len); } else if (key->nw_proto == IPPROTO_SCTP) { - return (!related || check_l4_sctp(data, size, validate_checksum)) + return (!related || check_l4_sctp(pkt, data, size)) && extract_l4_sctp(key, data, size, chk_len); } else if (key->dl_type == htons(ETH_TYPE_IP) && key->nw_proto == IPPROTO_ICMP) { - return (!related || check_l4_icmp(data, size, validate_checksum)) + return (!related || check_l4_icmp(pkt, data, size)) && extract_l4_icmp(key, data, size, related, chk_len); } else if (key->dl_type == htons(ETH_TYPE_IPV6) && key->nw_proto == IPPROTO_ICMPV6) { - return (!related || check_l4_icmp6(key, data, size, l3, - validate_checksum)) + return (!related || check_l4_icmp6(pkt, key, data, size, l3)) && extract_l4_icmp6(key, data, size, related); } @@ -2246,8 +2269,8 @@ conn_key_extract(struct conntrack *ct, struct dp_packet *pkt, ovs_be16 dl_type, } else { /* Validate the checksum only when hwol is not supported and the * packet's checksum status is not known. */ - ok = extract_l3_ipv4(&ctx->key, l3, dp_packet_l3_size(pkt), NULL, - dp_packet_ip_checksum_unknown(pkt)); + ok = extract_l3_ipv4(pkt, &ctx->key, l3, dp_packet_l3_size(pkt), + NULL); } } else if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) { ok = extract_l3_ipv6(&ctx->key, l3, dp_packet_l3_size(pkt), NULL); @@ -2258,10 +2281,8 @@ conn_key_extract(struct conntrack *ct, struct dp_packet *pkt, ovs_be16 dl_type, if (ok) { if (!dp_packet_l4_checksum_bad(pkt)) { /* Validate the checksum only when hwol is not supported. */ - if (extract_l4(&ctx->key, l4, dp_packet_l4_size(pkt), - &ctx->icmp_related, l3, - dp_packet_l4_checksum_unknown(pkt), - NULL)) { + if (extract_l4(pkt, &ctx->key, l4, dp_packet_l4_size(pkt), + &ctx->icmp_related, l3, NULL)) { ctx->hash = conn_key_hash(&ctx->key, ct->hash_basis); return true; } diff --git a/lib/ipf.c b/lib/ipf.c index 0b7ca5bd28..6670ef5a99 100644 --- a/lib/ipf.c +++ b/lib/ipf.c @@ -618,7 +618,12 @@ ipf_is_valid_v4_frag(struct ipf *ipf, struct dp_packet *pkt) bool bad_csum = dp_packet_ip_checksum_bad(pkt); if (OVS_UNLIKELY(!bad_csum && dp_packet_ip_checksum_unknown(pkt))) { COVERAGE_INC(ipf_l3csum_checked); - bad_csum = csum(l3, ip_hdr_len); + if (csum(l3, ip_hdr_len)) { + dp_packet_ip_checksum_set_bad(pkt); + bad_csum = true; + } else { + dp_packet_ip_checksum_set_good(pkt); + } } if (OVS_UNLIKELY(bad_csum)) { COVERAGE_INC(ipf_l3csum_err); diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c index e070088259..86e46b173e 100644 --- a/lib/netdev-native-tnl.c +++ b/lib/netdev-native-tnl.c @@ -120,7 +120,12 @@ ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, * csum already checked. In this case, skip the check. */ if (OVS_UNLIKELY(!bad_csum && dp_packet_ip_checksum_unknown(packet))) { COVERAGE_INC(native_tnl_l3csum_checked); - bad_csum = csum(ip, IP_IHL(ip->ip_ihl_ver) * 4); + if (csum(ip, IP_IHL(ip->ip_ihl_ver) * 4)) { + dp_packet_ip_checksum_set_bad(packet); + bad_csum = true; + } else { + dp_packet_ip_checksum_set_good(packet); + } } if (OVS_UNLIKELY(bad_csum)) { COVERAGE_INC(native_tnl_l3csum_err); @@ -246,7 +251,12 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, ((const unsigned char *)udp - (const unsigned char *)dp_packet_eth(packet) )); - bad_csum = csum_finish(csum); + if (csum_finish(csum)) { + dp_packet_l4_checksum_set_bad(packet); + bad_csum = true; + } else { + dp_packet_l4_checksum_set_good(packet); + } } if (OVS_UNLIKELY(bad_csum)) { COVERAGE_INC(native_tnl_l4csum_err);