From patchwork Sat Jan 13 08:00:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Github ODP bot X-Patchwork-Id: 124418 Delivered-To: patch@linaro.org Received: by 10.46.64.148 with SMTP id r20csp65406lje; Sat, 13 Jan 2018 00:05:00 -0800 (PST) X-Google-Smtp-Source: ACJfBouCB+KX/xsG6Hxpvgji0BpjhZIkdwXp8sqQmDthS7AGTHxQXwl1ubHcUGH5o3+XKLTuF5L2 X-Received: by 10.200.42.135 with SMTP id b7mr40725855qta.321.1515830700410; Sat, 13 Jan 2018 00:05:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1515830700; cv=none; d=google.com; s=arc-20160816; b=yYw5gBja688LwpiFJ4/vDIH1HDY1wGzn22asLcLBPd2dsE0a5Vv3OFJiFhIV18zy3U lBWcH6BBxtJY8srZLrWSvI0J27jTnFD/IXVibs5VYmgX/Gqz0lGGlXEf/VFuNdmqbi6S +vy/ZWfLdNPCtbQTMKXJ5ocf6z1co9Hnvor2Gny64J7Q0zIjsESW9BXtOsoRpEXT/Aar gqV1b1xEPiffSF9/0ARrTm41FMRROWbI7KCf8P/nwKhev8ccFujH7pIwSw3X3jwMqHal RDcEbiTm0YqKX6hFhlYzHU2l7TCpWq5Ye+ARavw6W2DscfpTMXOc2dXH87waPuLGfHax m9KA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:github-pr-num :references:in-reply-to:message-id:date:to:from:delivered-to :arc-authentication-results; bh=xrgiyI5Wjr7L8hN+Da3hfDuVgLSz3aXly4qSz4N6CgY=; b=qfE+hZopBlK6otPktOVcl+w6wHjtV5CerXAodeLmzgCoSexTgdFAapnMgmBnrEuxaL d+iwitleLmjXoVd1uFclEwYMjk1N5175jK9kVXPRRaF39hGSa+qbsv4JkR4O3RtvXey5 w/6aS4n5nzGHQVTKP4y6wASjP405gaXt7FLMk5bpnQF8+4da3vFolB5pYRed/VFt7KrP Ga2KuFTHJ3ufrKSr03jCBhiLWXDb4Endfma+N4GdSSqYrdvZIIWtpwGTVDNbhNpvZYJA OIm5m2uXNDWuEqXWg+AEOmxhlty938VemC15skf1bZ6P/YTehx9o3UpFYtapyzv/pKZn Mrhg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.197.127.237 as permitted sender) smtp.mailfrom=lng-odp-bounces@lists.linaro.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=yandex.ru Return-Path: Received: from lists.linaro.org (ec2-54-197-127-237.compute-1.amazonaws.com. [54.197.127.237]) by mx.google.com with ESMTP id m63si3438592qke.337.2018.01.13.00.05.00; Sat, 13 Jan 2018 00:05:00 -0800 (PST) Received-SPF: pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.197.127.237 as permitted sender) client-ip=54.197.127.237; Authentication-Results: mx.google.com; spf=pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.197.127.237 as permitted sender) smtp.mailfrom=lng-odp-bounces@lists.linaro.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=yandex.ru Received: by lists.linaro.org (Postfix, from userid 109) id 23368607A9; Sat, 13 Jan 2018 08:05:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on ip-10-142-244-252 X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2 autolearn=disabled version=3.4.0 Received: from [127.0.0.1] (localhost [127.0.0.1]) by lists.linaro.org (Postfix) with ESMTP id 8B4C161778; Sat, 13 Jan 2018 08:00:52 +0000 (UTC) X-Original-To: lng-odp@lists.linaro.org Delivered-To: lng-odp@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id 70B9F61765; Sat, 13 Jan 2018 08:00:32 +0000 (UTC) Received: from forward101o.mail.yandex.net (forward101o.mail.yandex.net [37.140.190.181]) by lists.linaro.org (Postfix) with ESMTPS id 6525161750 for ; Sat, 13 Jan 2018 08:00:14 +0000 (UTC) Received: from mxback16j.mail.yandex.net (mxback16j.mail.yandex.net [IPv6:2a02:6b8:0:1619::92]) by forward101o.mail.yandex.net (Yandex) with ESMTP id 16EA51341C45 for ; Sat, 13 Jan 2018 11:00:13 +0300 (MSK) Received: from smtp4j.mail.yandex.net (smtp4j.mail.yandex.net [2a02:6b8:0:1619::15:6]) by mxback16j.mail.yandex.net (nwsmtp/Yandex) with ESMTP id ZUli9oBvJj-0CG4VfnE; Sat, 13 Jan 2018 11:00:13 +0300 Received: by smtp4j.mail.yandex.net (nwsmtp/Yandex) with ESMTPSA id 8Hzdfi2ypg-0CYex1di; Sat, 13 Jan 2018 11:00:12 +0300 (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (Client certificate not present) From: Github ODP bot To: lng-odp@lists.linaro.org Date: Sat, 13 Jan 2018 11:00:06 +0300 Message-Id: <1515830407-13301-7-git-send-email-odpbot@yandex.ru> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1515830407-13301-1-git-send-email-odpbot@yandex.ru> References: <1515830407-13301-1-git-send-email-odpbot@yandex.ru> Github-pr-num: 389 Subject: [lng-odp] [PATCH v2][WIP 6/7] linux-gen: packet: check UDP checksums X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "The OpenDataPlane \(ODP\) List" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: lng-odp-bounces@lists.linaro.org Sender: "lng-odp" From: Dmitry Eremin-Solenikov Add code to enable checking of UDP checksums. Signed-off-by: Dmitry Eremin-Solenikov --- /** Email created from pull request 389 (lumag:parse-checksums) ** https://github.com/Linaro/odp/pull/389 ** Patch: https://github.com/Linaro/odp/pull/389.patch ** Base sha: 49ebafae0edebbc750742d8874ad0a7588286dea ** Merge commit sha: 29d9c9fa8235c01897c72e823b57525e37f896d3 **/ .../linux-generic/include/odp_packet_internal.h | 6 + platform/linux-generic/odp_packet.c | 134 +++++++++++++++++++-- 2 files changed, 132 insertions(+), 8 deletions(-) diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h index 86f0d80a5..f8b698335 100644 --- a/platform/linux-generic/include/odp_packet_internal.h +++ b/platform/linux-generic/include/odp_packet_internal.h @@ -100,6 +100,12 @@ typedef struct { /* offset to L4 hdr (TCP, UDP, SCTP, also ICMP) */ uint16_t l4_offset; + + /* Partial sum for L4 checksumming */ + uint32_t l4_part_sum; + + /* L4 checksum */ + uint32_t l4_sum; } packet_parser_t; /* Packet extra data length */ diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c index d3c608ab0..4adffc66a 100644 --- a/platform/linux-generic/odp_packet.c +++ b/platform/linux-generic/odp_packet.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -1948,6 +1949,35 @@ int _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt) return dst_uarea_size < src_uarea_size; } +static uint16_t packet_sum_ones_comp16(odp_packet_hdr_t *pkt_hdr, + uint32_t offset, + uint32_t len) +{ + uint32_t sum = pkt_hdr->p.l4_part_sum; + odp_bool_t odd_offset = false; + + if (offset + len > pkt_hdr->frame_len) + return 0; + + while (len > 0) { + uint32_t seglen = 0; /* GCC */ + void *mapaddr = packet_map(pkt_hdr, offset, &seglen, NULL); + + if (seglen < len) + seglen = len; + + len -= seglen; + sum += _odp_chksum_ones_comp16_32(mapaddr, seglen, odd_offset); + odd_offset ^= (seglen % 2); + } + + /* Not more than two additions */ + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum; +} + /** Parser helper function for Ethernet packets */ static inline uint16_t parse_eth(packet_parser_t *prs, const uint8_t **parseptr, uint32_t *offset, uint32_t frame_len) @@ -2033,6 +2063,7 @@ static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr, uint16_t frag_offset; uint32_t dstaddr = odp_be_to_cpu_32(ipv4->dst_addr); uint32_t l3_len = odp_be_to_cpu_16(ipv4->tot_len); + uint32_t l4_part_sum = 0; if (odp_unlikely(ihl < _ODP_IPV4HDR_IHL_MIN) || odp_unlikely(ver != 4) || @@ -2052,6 +2083,18 @@ static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr, *offset += ihl * 4; *parseptr += ihl * 4; + if (chksums.chksum.udp || chksums.chksum.tcp) { + l4_part_sum = _odp_chksum_ones_comp16_32( + (const uint16_t *)&ipv4->src_addr, + 2 * _ODP_IPV4ADDR_LEN, false); +#if ODP_BYTE_ORDER == ODP_BIG_ENDIAN + l4_part_sum += ipv4->proto; +#else + l4_part_sum += ((uint16_t)ipv4->proto) << 8; +#endif + prs->l4_part_sum = l4_part_sum; + } + if (odp_unlikely(ihl > _ODP_IPV4HDR_IHL_MIN)) prs->input_flags.ipopt = 1; @@ -2076,13 +2119,15 @@ static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr, */ static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr, uint32_t *offset, uint32_t frame_len, - uint32_t seg_len) + uint32_t seg_len, + odp_proto_chksums_t chksums) { const _odp_ipv6hdr_t *ipv6 = (const _odp_ipv6hdr_t *)*parseptr; const _odp_ipv6hdr_ext_t *ipv6ext; uint32_t dstaddr0 = odp_be_to_cpu_32(ipv6->dst_addr.u8[0]); uint32_t l3_len = odp_be_to_cpu_16(ipv6->payload_len) + _ODP_IPV6HDR_LEN; + uint32_t l4_part_sum = 0; /* Basic sanity checks on IPv6 header */ if ((odp_be_to_cpu_32(ipv6->ver_tc_flow) >> 28) != 6 || @@ -2099,6 +2144,18 @@ static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr, *offset += sizeof(_odp_ipv6hdr_t); *parseptr += sizeof(_odp_ipv6hdr_t); + if (chksums.chksum.udp || chksums.chksum.tcp) { + l4_part_sum = _odp_chksum_ones_comp16_32( + (const uint16_t *)&ipv6->src_addr, + 2 * _ODP_IPV6ADDR_LEN, false); +#if ODP_BYTE_ORDER == ODP_BIG_ENDIAN + l4_part_sum += ipv6->next_hdr; +#else + l4_part_sum += ((uint16_t)ipv6->next_hdr) << 8; +#endif + prs->l4_part_sum = l4_part_sum; + } + /* Skip past any IPv6 extension headers */ if (ipv6->next_hdr == _ODP_IPPROTO_HOPOPTS || ipv6->next_hdr == _ODP_IPPROTO_ROUTE) { @@ -2155,14 +2212,35 @@ static inline void parse_tcp(packet_parser_t *prs, /** * Parser helper function for UDP */ -static inline void parse_udp(packet_parser_t *prs, - const uint8_t **parseptr, uint32_t *offset) +static inline void parse_udp(packet_parser_t *prs, const uint8_t **parseptr, + uint32_t *offset, odp_proto_chksums_t chksums) { const _odp_udphdr_t *udp = (const _odp_udphdr_t *)*parseptr; uint32_t udplen = odp_be_to_cpu_16(udp->length); - if (odp_unlikely(udplen < sizeof(_odp_udphdr_t))) + if (odp_unlikely(udplen < sizeof(_odp_udphdr_t))) { prs->error_flags.udp_err = 1; + return; + } + + if (chksums.chksum.udp && + !prs->input_flags.ipfrag) { + if (udp->chksum == 0) { + prs->input_flags.l4_chksum_done = + (prs->input_flags.ipv4 != 1); + prs->error_flags.l4_chksum = + (prs->input_flags.ipv4 != 1); + } else { + prs->input_flags.l4_chksum_done = 1; + prs->l4_part_sum += udp->length; + /* Do not include checksum into partial sum */ + prs->l4_part_sum += _odp_chksum_ones_comp16_32( + (const void *)udp, + _ODP_UDPHDR_LEN - 2, + false); + } + prs->l4_sum = udp->chksum; + } if (odp_cpu_to_be_16(_ODP_UDP_IPSEC_PORT) == udp->dst_port && udplen > 4) { @@ -2208,7 +2286,7 @@ int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr, case _ODP_ETHTYPE_IPV6: prs->input_flags.ipv6 = 1; ip_proto = parse_ipv6(prs, &parseptr, &offset, frame_len, - seg_len); + seg_len, chksums); prs->l4_offset = offset; break; @@ -2252,7 +2330,7 @@ int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr, if (odp_unlikely(offset + _ODP_UDPHDR_LEN > seg_len)) return -1; prs->input_flags.udp = 1; - parse_udp(prs, &parseptr, NULL); + parse_udp(prs, &parseptr, NULL, chksums); break; case _ODP_IPPROTO_AH: @@ -2309,6 +2387,35 @@ int packet_parse_common(packet_parser_t *prs, const uint8_t *ptr, seg_len, layer, ethtype, chksums); } +static int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr, + odp_proto_chksums_t chksums) +{ + /* UDP chksum == 0 case is covered in parse_udp() */ + if (chksums.chksum.udp && + pkt_hdr->p.input_flags.udp && + !pkt_hdr->p.input_flags.ipfrag && + pkt_hdr->p.l4_sum != 0) { + uint16_t sum = packet_sum_ones_comp16(pkt_hdr, + pkt_hdr->p.l4_offset + + _ODP_UDPHDR_LEN, + pkt_hdr->frame_len - + pkt_hdr->p.l4_offset - + _ODP_UDPHDR_LEN); + + if (sum == 0) + sum = 0xffff; + + if (sum != pkt_hdr->p.l4_sum) { + pkt_hdr->p.error_flags.l4_chksum = 1; + ODP_DBG("UDP chksum fail (%x)!\n", sum); + } else { + ODP_DBG("UDP chksum OK!\n"); + } + } + + return pkt_hdr->p.error_flags.all != 0; +} + /** * Simple packet parser */ @@ -2318,9 +2425,15 @@ int packet_parse_layer(odp_packet_hdr_t *pkt_hdr, { uint32_t seg_len = packet_first_seg_len(pkt_hdr); void *base = packet_data(pkt_hdr); + int rc; + + rc = packet_parse_common(&pkt_hdr->p, base, pkt_hdr->frame_len, + seg_len, layer, chksums); - return packet_parse_common(&pkt_hdr->p, base, pkt_hdr->frame_len, - seg_len, layer, chksums); + if (rc != 0) + return rc; + + return packet_l4_chksum(pkt_hdr, chksums); } int odp_packet_parse(odp_packet_t pkt, uint32_t offset, @@ -2363,7 +2476,12 @@ int odp_packet_parse(odp_packet_t pkt, uint32_t offset, layer, ethtype, param->chksums); + if (ret) + return -1; + } + if (layer == ODP_PROTO_LAYER_L4) { + ret = packet_l4_chksum(pkt_hdr, param->chksums); if (ret) return -1; }