This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] AM625:IPv6 UDP 校验和卸载会产生非法校验和=0

Guru**** 2465890 points
Other Parts Discussed in Thread: AM625, SK-AM62

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1467179/am625-ipv6-udp-checksum-offload-produces-illegal-checksum-0

器件型号:AM625
主题中讨论的其他器件: SK-AM62

工具与软件:

尊敬的专家:

我的主要问题是尝试使用 tftp 从 AM625 Linux 用户空间下载大文件时出现可重复的超时。 有趣的是、这可以通过 IPv4连接到 tftp 服务器(我的笔记本电脑)、但现在我尝试通过 IPv6链路本地连接来实现。  请注意、我的设置使用 IPv6上的 UDP。

使用 tftp 服务器上的 Wireshark 调试时、我注意到下载在从 AM625发送到我的笔记本电脑的 UDP 封装校验和到达零时超时。 (UDP 数据包内容是一些 ACK 消息、数据包 ID 向上计数、因此 UDP 校验和从某个初始值向下计数到零。) 似乎我的笔记本电脑放弃了带有 UDP 校验和0的 ACK 响应、这是 RFC 2460的强制要求、它描述了 IPv6上的 UDP:

o 与 IPv4不同、当 UDP 数据包由 IPv6节点发起时、
UDP 校验和不是可选的。 发送信号
IPv6节点必须在源自 UDP 数据包时计算 UDP
以及伪标头(如有)上的校验和
计算得出结果为零、必须将其更改为十六进制
用于放置在 UDP 标头中的 FFFF。 IPv6接收器必须
丢弃包含零校验和的 UDP 数据包、并应记录下来
误差。 [强调地雷] 


暂时我可以使用来解决该问题  

ethtool --offload eth0 tx off
 在 tftp 下载之前;但是、如果我理解正确、这将为所有 TCP 和 UDP 通信的所有互联网校验和计算(之后在生产环境中)增加 CPU 的负担。

为了验证该问题、我编写了一个小的 python 脚本来发送某个小的 UDP 软件包、经过改编后的 UDP 校验和为零(经过一些试错)。

import socket
from time import sleep
from itertools import cycle

ip6 = "fe80::443a:64c4:2cd8:fd26"
dev = "eth0"
addr = f"{ip6}%{dev}"
port = 8648

family, type_, proto, canonname, sockaddr = socket.getaddrinfo(
    addr,
    port,
    family=socket.AF_INET6,
    type=socket.SOCK_DGRAM,
    proto=socket.IPPROTO_UDP,
).pop()

sock_send = socket.socket(family=family, type=type_, proto=proto)
sock_send.sendto(b"t0z-\r\n", sockaddr)  # effects UDP_checksum == 0 

实际上、硬件卸载逻辑似乎错误地处理了零情况(应将0x0000替换为0xFFFF)。 INSEAD 是 UDP 数据包通过 UDP 校验和零发送的、如接收端通过 Wireshark 指示:

问题:我们是否遗漏了 AM625硬件的某些配置、该配置改变了特殊情况(0 --> 0xFFFF)下的 IPv6-UDP-校验和的计算? 或者这是硬件错误吗、我们必须使用由软件计算的 UDP-Checksums。

提前感谢此致、
Lukas Rauber

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好、Lukas、

    感谢您介绍调试过程的详细信息。 首先、我们有几个关于您的测试设置的问题:

    1.您是否使用 AM625或 TI AM62x SK-EVM 在定制设计电路板上测试此功能?

    2.您使用的 Linux 处理器 SDK 版本是什么?

    3.如果您发现此问题是由于在定制设计电路板上进行的测试而导致的、您是否能够在 TI AM62x SK-EVM 上看到相同的问题?

    4.您的测试拓扑是什么? (即、您待测的 AM62x 器件是否通过 eth0直接连接到笔记本电脑、两者之间是否没有切换? 在测试过程中、AM62x 器件上没有连接其他以太网端口?)

    -道林

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Daolin

    感谢您的快速响应。 关于您的问题:

    1. 我们使用 Phytec SoM (phyCORE-AM62x)、它上面有一个 AM625 SoC。 此 SoM 安装在我们定制的电路板上。
    2. 最近、我们转换了 Phytec 的 BSP-Yocto-atriphy-AM62x-PD24.1.0主板支持包、它附带了:
      • - Linux TI 供应商内核 v6.6.6.6.6.32 (基于 TI 标签10.00.08)
        - U-Boot TI 供应商 v2024.04 (基于 TI 标签10.00.08)
        - Yocto 5.0.3 (Scarthgap)
        - Qt 6.6 
    3. 白天、我将尝试使用 TI AM62 SK-EVM 执行测试。
    4. 一个以太网端口(eth0)直接连接到我的笔记本电脑。 未使用另一个端口(eth1)。 端口未桥接(没有`br0`网络设备)。

    器件从 SD 卡引导、因为在我们的引导过程中发生了问题(从 SD 卡引导到 eMMC)。

    我使用 USB UART 适配器通过 UART0访问了 AM625的外壳、该外壳也连接至我的笔记本电脑。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    最新动态:

    3.) 实际上、还可以在 TI SK-AM62上找到问题、其中带有 TI 映像`tisdk-default-image-am62xx-evm-10.01.10.04.rootfs.wic.xz — 1017665K `:

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Lukas:  

    >> 3.) 实际上、还可以在 TI SK-AM62上找到问题、其中带有 TI 映像`tisdk-default-image-am62xx-evm-10.01.10.04.rootfs.wic.xz  — 1017665K `:

    感谢您的确认。  

    您能分享以下内容吗? 请在 TI SK-AM62 EVM 上执行此操作、因为我可以更轻松地在我这边研究这个问题。

    1.在"ethtool --卸载 eth0 tx off"之前和之后的"ethtool -k eth0"结果?

    2.在非法 UDP 校验和消息前后的 ethtool -S eth0的结果?

    3.在发送 UDP 数据包时、这些数据包是从您的主机笔记本电脑发送到被测 AM62x 器件的? (即 AM62x 正在接收 UDP 数据包、还是发送 UDP 数据包?)

    4.如果您将校验和为0的 UDP 数据包从主机笔记本电脑发送到被测 AM62x 器件、您是否看到 UDP Rx 校验和卸载有问题?

    -道林

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Lukas:

    再次感谢您分享这些详细信息。 我需要一些时间在内部对此进行研究(在内部与一些同事讨论并复制此问题)、我的计划是明天处理此问题、并在星期五提供最新情况。  

    同时、您是否已了解使用"ethtool --offload eth0 tx off"时 CPU 负载增加了多少? 我知道、虽然 CPU 负载会在禁用 TX 校验和卸载的情况下增加、但实际负载不会大幅增加。 如果 CPU 负载仍然满足您的要求、在跟踪此问题的根本原因之前、可以将它作为一种权变措施。

    -道林

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    最新动态:

    我可以使用 python 脚本复制同一个问题。 我将为此创建一个内部错误通知单、以解决该问题。 我怀疑 CPSW 驱动程序的以下部分没有处理 IPv6 UDP 传输校验和为0x0的情况、并确保校验和作为0xFFFF 发送。 开发人员可能需要一些时间来修复此问题、因此请随意尝试修改 CPSW 驱动程序(am65-cpsw-nuss.c)、以查看是否可以使 TX 卸载校验和正常工作。

    https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/drivers/net/ethernet/ti/am65-cpsw-nuss.c?h=ti-rt-linux-6.6.y&id=93a76530316a3d8cc2d82c3deca48424fee92100#n1031   

    涵盖 TX-CHECKSUM-OFFLOAD 的原始补丁: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/commit/drivers/net/ethernet/ti/am65-cpsw-nuss.c?h=ti-rt-linux-6.6.y&id=93a76530316a3d8cc2d82c3deca48424fee92100 

    此部分驱动程序中提到的勘误表似乎仅适用于 AM65x 器件、不在 AM62x 的勘误表中: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/drivers/net/ethernet/ti/am65-cpsw-nuss.c?h=ti-rt-linux-6.6.y&id=93a76530316a3d8cc2d82c3deca48424fee92100#n1683 

    -道林

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Lukas:

    我最近与我们的内部团队讨论过、似乎需要启用 RX 控制数据字2寄存器中的 CHECKSUM_INV 位、以确保将零校验和值反转并作为0xFFFF 发送(请参阅 AM62x TRM 中的以下内容)。   

    请注意、此处 TRM 中的 RX 是从 CPPI 内部端口来看的、因此从 CPU 到主机端口、然后从主机端口到其中一个外部端口、这本质上是 TX 校验和处理。

    开发人员给出的一项建议是 在 CPSW 驱动程序中无条件地设置所有数据包(包括 UDP 和 TCP)的 CHECKSUM_INV 位、如下所示。 请注意、这样做会导致即使校验和为0的 IPv4数据包也会将校验和反转为0xFFFF。 对于某些数据包、不应进行这种反转、因为 零校验和对 IPv4上的 TCP 和 IPv6上的 UDP 有效、但对 IPv6上的 UDP 无效。  

    diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
    index 3d378920e65c..89329ddbb231 100644
    --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
    +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
    @@ -1745,7 +1745,8 @@ static netdev_tx_t am65_cpsw_nuss_ndo_slave_xmit(struct sk_buff *skb,
                    cs_offset = cs_start + skb->csum_offset;
                    /* HW numerates bytes starting from 1 */
                    psdata[2] = ((cs_offset + 1) << 24) |
    -                           ((cs_start + 1) << 16) | (skb->len - cs_start);
    +                           ((cs_start + 1) << 16) | (skb->len - cs_start)
    +                           | BIT(15); // BIT(15) enables csum inversion for zero csum
                    dev_dbg(dev, "%s tx psdata:%#x\n", __func__, psdata[2]); 

    另一种选项是确定数据包是否为 UDP IPv6、并选择性地设置 CHECKSUM_INV 位、但这会妨碍将校验和计算卸载到硬件的目的。  

    请告诉我们您的想法。

    -道林

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Daolin:

    感谢您提供的宝贵意见、非常感谢您提供的有用而简明的信息。

    如果我们无条件设置 CHECKSUM_INV 位、我们目前不确定是否会在稍后阶段潜入陷阱、尤其是对于基于 IPv4的 TCP 包。 唉,当禁用校验和计算卸载时,额外的 CPU 使用似乎根本不会明显阻碍我们的系统。

    现在、我们将使用软件计算校验和(即禁用 TX 卸载)。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    iff --git a/linux/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/linux/drivers/net/ethernet/ti/am65-cpsw-nuss.c
    index 81d48e84234..59502664fa1 100644
    --- a/linux/drivers/net/ethernet/ti/am65-cpsw-nuss.c
    +++ b/linux/drivers/net/ethernet/ti/am65-cpsw-nuss.c
    @@ -9,6 +9,8 @@
     #include <linux/etherdevice.h>
     #include <linux/if_vlan.h>
     #include <linux/interrupt.h>
    +#include <linux/ip.h>
    +#include <linux/ipv6.h>
     #include <linux/irqdomain.h>
     #include <linux/kernel.h>
     #include <linux/kmemleak.h>
    @@ -1159,6 +1161,14 @@ static netdev_tx_t am65_cpsw_nuss_ndo_slave_xmit(struct sk_buff *skb,
                    /* HW numerates bytes starting from 1 */
                    psdata[2] = ((cs_offset + 1) << 24) |
                                ((cs_start + 1) << 16) | (skb->len - cs_start);
    +               /* UDP checksum 0 must be written as 0xFFFF. This is done by setting the CHECKSUM_INV bit. */
    +               if (skb_headlen(skb) >= skb_transport_offset(skb)) {
    +                       if ((skb->protocol == htons(ETH_P_IP)   && ip_hdr(skb)->protocol  == IPPROTO_UDP) ||
    +                           (skb->protocol == htons(ETH_P_IPV6) && ipv6_hdr(skb)->nexthdr == IPPROTO_UDP))
    +                               psdata[2] |= 0x8000; // set CHECKSUM_INV bit
    +               } else
    +                       dev_dbg(dev, "SKB header fragmented!\n");
    +
                    dev_dbg(dev, "%s tx psdata:%#x\n", __func__, psdata[2]);
            }
     
    

    这就是我们使用的方法。 我实在是太懒了,还不敢把它上游起来。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Ronald:  

    感谢您在此主题中共享您的补丁!

    您的补丁似乎执行了 UDP IPv6检查并选择性地设置 CHECKSUM_INV 位。

    作为未来读者的注意事项(如前所述)、这 抵消了将校验和计算卸载到硬件的目的、因为我们现在有在有条件地设置"chksum_inv"位之前解析所有数据包标头的开销、因此、在尝试实施此解决方案时请注意这一点。

    -道林

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    该校验只有标头中的几个字节、而校验和计算稍微更昂贵一些、因为它必须将数据包中的所有数据累加。 因此、我不确定这是否会完全抵消硬件校验和计算的损失。 我有什么误解吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    >>因此、我不确定这是否完全抵消了硬件校验和计算。 我有什么误解吗?

    开发人员在内部讨论此主题时、也分享了有关破坏卸载校验和计算目的的注意事项。 您会发现、与数据包中所有字节的校验和计算相比、检查标头仅几个字节。 我猜是、我们的开发人员意味着 分析所有要传输的数据包的操作可能会占用足够的负载、从而抵消校验和卸载带来的任何负载减少。 在这种情况下、可能会考虑到、根据我的理解、如果不卸载校验和、实际加载不会大幅增加(换句话说、由于卸载了校验和、加载益处不会大幅增加)。

    不过、通过测量负载来判断实际情况是否确实如此(如果 CPU 负载是问题)可能是值得的、因为我所描述的所有这些内容目前都是推测性的。

    -道林

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    实际上没有必要解析标头。 skb 数据被映射到存储器中、并且要检查的字节偏移量是已知的。 您不必是一个天才,看到检查一些字节在加载和加载和整个有效负载是一个巨大的差异。 到底是否真的很重要是另一个问题。 对于正常用例、它可能可以忽略不计、但内核不应对此进行假设。 如果我找到时间、我将进行一些测量。 我会一直上传补丁、当时很可能会得到 TI 人员的审阅。