网络设备功能混乱以及如何从中脱身¶
- 作者
Michał Mirosław <mirq-linux@rere.qmqm.pl>
第一部分:功能集¶
网络卡仅仅接收并原样发送数据包的日子早已远去。今天的设备添加了多种功能和错误(读作:卸载),以减轻操作系统各种任务的负担,例如生成和检查校验和、分割数据包、对其进行分类。这些功能及其状态在 Linux 内核世界中通常被称为网络设备功能。
目前,有三组功能与驱动程序相关,一组供网络核心内部使用。
netdev->hw_features 集合包含的功能的状态可能通过用户的请求为特定设备更改(启用或禁用)。此集合应在 ndo_init 回调中初始化,之后不再更改。
netdev->features 集合包含当前为设备启用的功能。这应该仅由网络核心更改,或者在 ndo_set_features 回调的错误路径中更改。
netdev->vlan_features 集合包含其状态由子 VLAN 设备继承的功能(限制 netdev->features 集合)。目前,无论是在硬件还是软件中剥离或插入标签,这都用于所有 VLAN 设备。
netdev->wanted_features 集合包含用户请求的功能集。每当它或某些特定于设备的条件发生更改时,此集合都会通过 ndo_fix_features 回调进行筛选。此集合是网络核心的内部集合,不应在驱动程序中引用。
第二部分:控制启用的功能¶
当需要更改当前功能集 (netdev->features) 时,会计算新的集合,并通过调用 ndo_fix_features 回调和 netdev_fix_features() 进行筛选。如果结果集与当前集不同,则会将其传递给 ndo_set_features 回调,并且(如果回调返回成功)替换存储在 netdev->features 中的值。之后,每当当前集可能已更改时,都会发出 NETDEV_FEAT_CHANGE 通知。
- 以下事件会触发重新计算
设备注册,在 ndo_init 返回成功之后
用户请求更改功能状态
在持有 rtnl_lock 的情况下调用 ndo_*_features 回调。缺少的回调将被视为始终返回成功。
想要触发重新计算的驱动程序必须在持有 rtnl_lock 的情况下调用 netdev_update_features()
来完成此操作。不应从 ndo_*_features 回调执行此操作。除了通过 ndo_fix_features 回调之外,驱动程序不应修改 netdev->features。
第三部分:实现提示¶
ndo_fix_features
此处应解析功能之间的所有依赖关系。网络核心施加的限制(如 netdev_fix_features() 中编码的那样)可以进一步减少结果集。因此,当不满足依赖关系时,禁用功能比强制依赖关系更安全。
此回调不应修改硬件或驱动程序状态(应是无状态的)。它可以在连续的 ndo_set_features 调用之间被多次调用。
回调不得更改 NETIF_F_SOFT_FEATURES 或 NETIF_F_NEVER_CHANGE 集中包含的功能。例外情况是 NETIF_F_VLAN_CHALLENGED,但必须小心,因为更改不会影响已配置的 VLAN。
ndo_set_features
应重新配置硬件以匹配传递的功能集。除非发生无法在 ndo_fix_features 中可靠检测到的一些错误情况,否则不应更改该集合。在这种情况下,回调应更新 netdev->features 以匹配结果硬件状态。返回的错误不会(并且不能)传播到任何地方,除了 dmesg。(注意:成功返回为零,>0 表示静默错误。)
第四部分:功能¶
有关当前功能列表,请参阅 include/linux/netdev_features.h。本节描述其中一些功能的语义。
传输校验和
有关完整说明,请参阅 include/linux/skbuff.h 顶部附近的注释。
注意:NETIF_F_HW_CSUM 是 NETIF_F_IP_CSUM + NETIF_F_IPV6_CSUM 的超集。这意味着设备可以在数据包中的任何位置填充 TCP/UDP 类的校验和,无论那里可能有哪些标头。
传输 TCP 分段卸载
NETIF_F_TSO_ECN 表示硬件可以正确拆分设置了 CWR 位的数据包,无论是 TCPv4(当启用 NETIF_F_TSO 时)还是 TCPv6 (NETIF_F_TSO6)。
传输 UDP 分段卸载
NETIF_F_GSO_UDP_L4 接受带有超出 gso_size 的有效负载的单个 UDP 标头。在分段时,它会在 gso_size 边界上分割有效负载,并复制网络和 UDP 标头(如果小于 gso_size,则修复最后一个标头)。
从高内存传输 DMA
在相关平台上,NETIF_F_HIGHDMA 表示 ndo_start_xmit 可以处理高内存中的 frags 的 skb。
传输分散/收集
这些功能表明 ndo_start_xmit 可以处理分段的 skb:NETIF_F_SG --- 分页的 skb (skb_shinfo()->frags),NETIF_F_FRAGLIST --- 链接的 skb (skb->next/prev 列表)。
软件功能
NETIF_F_SOFT_FEATURES 中包含的功能是网络堆栈的功能。驱动程序不应基于这些功能更改行为。
VLAN 挑战
对于无法处理 VLAN 标头的设备,应设置 NETIF_F_VLAN_CHALLENGED。一些驱动程序设置此项是因为卡无法处理更大的 MTU。[FIXME:这些情况可以通过仅允许减少 MTU 的 VLAN 来在 VLAN 代码中修复。但这可能没有用。]
rx-fcs
这请求网卡将以太网帧校验和 (FCS) 附加到 skb 数据的末尾。这允许嗅探器和其他工具读取网卡在接收数据包时记录的 CRC。
rx-all
这请求网卡接收所有可能的帧,包括出错的帧(例如错误的 FCS 等)。当嗅探链路上的坏包时,这可能会有所帮助。如果同时将某些网卡置于正常的混杂模式,它们可能会接收到更多数据包。
rx-gro-hw
这请求网卡启用硬件 GRO(通用接收卸载)。硬件 GRO 基本上是 TSO 的完全相反,并且通常比硬件 LRO 更严格。硬件 GRO 合并的数据包流必须可以通过 GSO 或 TSO 重新分段回完全原始的数据包流。硬件 GRO 依赖于 RXCSUM,因为硬件成功合并的每个数据包也必须由硬件验证校验和。
hsr-tag-ins-offload
对于自动插入 HSR(高可用性无缝冗余)或 PRP(并行冗余协议)标签的设备,应设置此项。
hsr-tag-rm-offload
对于自动删除 HSR(高可用性无缝冗余)或 PRP(并行冗余协议)标签的设备,应设置此项。
hsr-fwd-offload
对于在硬件中将 HSR(高可用性无缝冗余)帧从一个端口转发到另一个端口的设备,应设置此项。
hsr-dup-offload
对于在硬件中自动复制传出的 HSR(高可用性无缝冗余)或 PRP(并行冗余协议)标签的帧的设备,应设置此项。