Linux网卡诊断工具-ethtool
2012-10-14 13:35:06 阿炯

ethtool 是一个 Linux 下的网络驱动程序的诊断和调整工具,可获取网络设备(网卡)的相关信息,包括连接状态、驱动版本、PCI 总线定位等等。

utility for controlling network drivers and hardware.

常见支持的特性:
Get identification and diagnostic information,获取识别和诊断信息

Get extended device statistics,获取扩展设备统计信息

Control speed, duplex, autonegotiation and flow control for Ethernet devices,控制速度,双工,自动协商和以太网设备的流量控制

Control checksum offload and other hardware offload features,控制校验和卸载和其他硬件卸载功能

Control DMA ring sizes and interrupt moderation,控制DMA环大小和中断调节

Control receive queue selection for multiqueue devices,控制多队列设备的接收队列选择

Upgrade firmware in flash memory,升级闪存固件

ethtool目前几乎所有的网卡驱动程序都有对其有支持,可以用于网卡状态/驱动版本信息查询、收发数据信息查询及能力配置以及网卡工作模式/链路速度等查询配置。用于查看和修改网络设备(尤其是有线以太网设备)的驱动参数和硬件设置。它可以用来:
获取标识和诊断信息
获取扩展的设备统计信息
控制以太网设备的速度、双工、自动协商和流控制
控制校验和卸载及其他硬件卸载功能
控制 DMA 环大小及中断控制
控制多队列设备的接收队列选择
升级闪存中的固件

网卡类设备的常见概念:
半双工:半双工模式允许设备一次只能发送或接收数据包。
全双工:全双工模式允许设备可以同时发送和接收数据包。
自动协商:自动协商是一种机制,允许设备自动选择最佳网速和工作模式(全双工或半双工模式)。
速度:默认情况下,它会使用最大速度,你可以根据自己的需要改变它。
链接检测:链接检测可以显示网卡的状态。如果显示为 no,请尝试重启网卡。如果链路检测仍显示 no,则检查交换机与系统之间连接的线缆是否有问题。

ethtool并不能查看所有类型网卡的参数,因为实际情况非常复杂,有些虚拟网卡查出来的参数很有限,有些物理网卡,但驱动被DPDK等其他程序接管,其效果也一般。

命令格式

ethtool [选项] [网卡]

选项

-a:查看网卡中接收模块RX、发送模块TX和Autonegotiate模块的状态:启动on 或 停用off。
-A:修改网卡中 接收模块RX、发送模块TX和Autonegotiate模块的状态:启动on 或 停用off。
-c:display the Coalesce(聚合、联合) information of the specified ethernet card.聚合网口信息,使看起来更有规律。
-C:Change the Coalesce setting of the specified ethernet card.修改网卡聚合信息。
-g:Display the rx/tx ring parameter information of the specified ethernet card. 显示网卡的接收/发送环形参数。
-G:Change the rx/tx ring setting of the specified ethernet card. 修改网卡的接收/发送环形参数。
-i:显示网卡驱动的信息,如驱动的名称、版本等。
-d:显示register dump信息, 部分网卡驱动不支持该选项。
-e:显示EEPROM dump信息,部分网卡驱动不支持该选项。
-E:修改网卡EEPROM byte.
-k:显示网卡Offload参数的状态:on 或 off,包括rx-checksumming、tx-checksumming等。
-K:修改网卡Offload参数的状态
-p:用于区别不同ethX对应网卡的物理位置,常用的方法是使网卡port上的led不断的闪;N指示了网卡闪的持续时间,以秒为单位。
-r:如果auto-negotiation模块的状态为on,则restarts auto-negotiation.
-s:修改网卡的部分配置,包括网卡速度、单工/全双工模式、mac地址等。加上-s选项修改的内容才会生效
-S:显示NIC and driver-specific 的统计参数,如网卡接收/发送的字节数、接收/发送的广播包个数等。
-t:让网卡执行自我检测,有两种模式:offline or online.

常用命令

查看类:

ethtool -h        显示ethtool的命令帮助(help)

ethtool ethx    #查看eth0网卡的基本设置,内容包括网卡速率、网卡的工作模式等,其中 x 是对应网卡的编号,如eth0、eth1等等

ethtool -i eth0      查看eth0网卡的驱动信息,内容包括驱动的型号、驱动的版本等

ethtool -d ethx      查询ethx网口注册性信息

ethtool -S ethx     查询ethx网口收发包统计(注意S是大写)

ethtool -r ethx      重置ethX网口到自适应模式

ethtool -g ethx     显示网卡的接收/发送环形参数。: 支持模式
Supported link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Supported pause frame use: No
Supports auto-negotiation: Yes: 支持自动协商
Supported FEC modes: Not reported: 通告模式
Advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Advertised pause frame use: No
Advertised auto-negotiation: Yes: 使用自动协商
Advertised FEC modes: Not reported
 
Speed: 1000Mb/s: 当前速率 1000Mb/s
Duplex: Full: 工作模式为全双工
 
Port: Twisted Pair
PHYAD: 0
Transceiver: internal
 
Auto-negotiation: on:自动协商打开
 
MDI-X: off (auto)
Supports Wake-on: d
Wake-on: d
Current message level: 0x00000007 (7)
drv probe link
Link detected: yes

#查询eth0对应哪张网卡
ethtool -p eth0 10  #对应网卡的LED灯闪烁,eth0就对应到那块物理网卡,持续10秒。

#查询网口的驱动相关信息
ethtool -i eth0

driver,网卡驱动的简短名字,不可以为空。
version,网卡驱动的版本。
firmware-version,网卡固件版本,可能为空。
expansion-rom-version,网卡扩展EPROM的版本,用于存储网卡的初始化代码。
bus-info,网卡的总线地址。
supports-statistics,网卡是否支持统计数据。
supports-test,网卡是否支持自身测试。
supports-eeprom-access,网卡是否支持访问EPROM。
supports-register-dump,网卡是否支持访问寄存器(能读取数据)。
supports-priv-flags,网卡是否支持私有的标志位。

ethtool -s [device_name] autoneg [on/off] speed [10/100/1000] duplex [half/full]

将enp0s1网上设备的自动协商功能打开并设置的速率模式为全双工Gbps。
ethtool -s enp0s1 autoneg on speed 1000 duplex full

如果网卡支持寄存器读取和eeprom,那么便可以输出更多信息了。
ethX查询ethx网口基本设置,其中x是对应网卡的编号,如eth0、eth1等。
-k查询网卡的Offload信息。
-K修改网卡的Offload信息。
-c查询网卡聚合信息。
-C修改网卡聚合信息。
-l查看网卡队列数。
-L设置网卡队列数。


另有-k,-c等选项。参数含义如下:
参数说明
rx-checksumming接收包校验和。
tx-checksumming发送包校验和。
scatter-gather分散-聚集功能,是网卡支持TSO的必要条件之一。
tcp-segmentation-offload简称为TSO,利用网卡对TCP数据包分片。
Combined网卡队列数。
adaptive-rx接收队列的动态聚合执行开关。
adaptive-tx发送队列的动态聚合执行开关。
tx-usecs产生一个中断之前至少有一个数据包被发送之后的微秒数。
tx-frames产生中断之前发送的数据包数量。
rx-usecs产生一个中断之前至少有一个数据包被接收之后的微秒数。
rx-frames产生中断之前接收的数据包数量。


协议负载信息

# 获取协议负载和其他特性信息
ethtool [ FLAGS ] -k|--show-features|--show-offload DEVNAME

# 设置协议负载和其他特性信息
ethtool [ FLAGS ] -K|--features|--offload DEVNAME FEATURE on|off ...

有较多的输出,对于常见的一些特性,ethtool会对它们进行分类(缩进输出),更多的命令则没有进行分类,而是无缩进输出。输出的信息中on表示当前对应特性开启了,off表示对应的特性没有开启。一般后面还会有一个中括号,里面放着一些额外的信息,如下:
fixed,表示该特性是固定的,也就是当前on/off状态不可改变。
request on,表示该特性应该被打开,但是当前状态是关闭。
request off,表示该特性应该被关闭,但是当前状态是打开。
空,表示该特性可自由开关。

ethtool内建的特性主要有以下这些种类:
rx on|off,是否使能接收校验和检测。
tx on|off,是否使能发送校验和检测。
sg on|off,是否开启Scatter/gather I/O 技术,从多个缓冲区发送数据。
tso on|off,是否使能TCP segmentation offload,允许上层应用发送大型数据包,由网卡自动分段发送。
ufo on|off,是否使能UDP fragmentation offload。
gso on|off,是否使能generic segmentation offload,通用负载分段,在TCP协议基础上支持更多其他协议分段。
lro on|off,是否使能large receive offload。
rxvlan on|off,是否使能rx vlan加速,由硬件处理vlan tag。
txvlan on|off,是否使能tx vlan加速,由硬件处理vlan tag。
ntuple on|off,是否使能RX n-元组过滤功能。
rxhash on|off,是否使用RX hashing offload,用于提升网络吞吐量。

具体的特性信息是Linux内核中列出的,因此这些特性可在内核代码include/linux/netdev_features.h头文件中查看。

设置类:

注意:该命令只是临时设置,如果网卡重启就失效了,如果想要永久保存应该配置 /etc/sysconfig/network-scripts/ifcfg-ethx 文件。

ethtool -s eth0 speed [10|100|1000]        # 设置网卡的速率,单位是:Mb/s

ethtool -s eth0 autoneg [on|off]        # 设置网卡是否自动协商,自动协商的内容主要包括工作模式、网卡速率以及流控等参数

ethtool -s ethX [speed 10|100|1000] [duplex half|full]  [autoneg on|off]        #设置网口速率10/100/1000M、设置网口半/全双工、设置网口是否自协商

ethtool -s eth0 autoneg off speed 100 duplex full # 也可以同时写在一起

ethtool -s eth0 duplex [half|full]    #设置网卡的工作模式,可设置为半双工或全双工

ethtool -G eth0 rx 4096 /ethtool -G eth0 tx 4096        #修改网卡的接收/发送环形参数。

ethtool -E eth0 magic 0x10798086 offset 0x10 value 0x1A   #修改网卡EEPROM内容(0x1079 网卡device id , 0x8086网卡verdor id  )

ethtool -e eth0  : dump网卡EEPROM内容

其他指令

ethtool -A tx off eth0    #停止网卡的发送模块TX

操作完毕后可输入:ethtool -a eth0    #查看tx模块是否已被停止。

ethtool -K eth0 rx off        #关闭网卡对收到的数据包的校验功能

操作完毕后可输入:ethtool -k eth0    #查看校验功能是否已被停止。

ethtool -p eth0 10     #如果机器上安装了两块网卡,查看eth0对应着哪块网卡

操作完毕后看哪块网卡的led灯在闪,eth0就对应着哪块网卡,前提是该网卡带有led指示灯。

ethtool通常是使用netlink来获取网卡驱动相关驱动信息的,另一种方式是ioctl,ioctl面对DPDK这样的场景就有一些不好用,因为内核里面并未保存着网卡信息。如果在用户态驱动的话,基本会监听netlink消息,因此一般还能获取和设置常见的参数。这里有必要说一下调试与监控模式。

--debug N通常是用来在netlink消息返回失败类型时,输出一些DEBUG信息,目前一共有以下几种类型:
DEBUG_PARSE = 0,
DEBUG_NL_MSGS = 1,        /* incoming/outgoing netlink messages */
DEBUG_NL_DUMP_SND = 2,        /* dump outgoing netlink messages */
DEBUG_NL_DUMP_RCV = 3,        /* dump incoming netlink messages */
DEBUG_NL_PRETTY_MSG = 4,    /* pretty print of messages and errors */

N是对应的掩码位,即N=31表示上面的全部DEBUG开关开启。

--monitor [command] [devname],可以监控netlink消息,后面command和devname能限定监控范围。不过如果ethtool编译时没有使能netlink,那么会不支持--monitor命令,或者连初始化也可能失败。

标识指定的接口

一般命令如下: # Show permanent hardware address
ethtool [ FLAGS ] -P|--show-permaddr DEVNAME
# Show visible port identification (e.g. blinking)
ethtool [ FLAGS ] -p|--identify DEVNAME [ TIME-IN-SECONDS ]

这两个命令可以标识对应的网卡设备,一般输出网卡的设备MAC地址:
# ethtool -P eth0
Permanent address: 00:20:5d:b1:43:11

重新自动协商
使用下面命令重新开始自动协商:
#  Restart N-WAY negotiation
ethtool [ FLAGS ] -r|--negotiate DEVNAME       

展示统计信息
# Show adapter statistics
ethtool [ FLAGS ] -S|--statistics DEVNAME [ --all-groups | --groups [eth-phy] [eth-mac] [eth-ctrl] [rmon] ]
# Show phy statistics
ethtool [ FLAGS ] --phy-statistics DEVNAME

网卡统计数据有很多,一些是标准的IEEE数据,一些是网卡标准的统计数据,还有一些是网卡设备特定的数据。不同类型的网卡统计数据是不同的,这些数据取决于对应的网卡类型以及它们的驱动。

由于软件统计数据和硬件统计数据在设计上是在包处理链的不同时刻增加的,因此很有可能传入的数据包在被硬件统计之后,但在到达软件统计数据之前就被丢弃了(很可能是组播数据包),而在相反的方式中,在传输过程中,FCS字节被添加在中间,TSO skb将被分割,头字节被添加。因此,使用ifconfig(软件)和ethtool(硬件)从用户空间收集的统计数据不能进行比较。实际的参数含义定义在内核网络驱动文件中,具体含义也要根据代码和文档确定,所以这里不再列出。

找到定义的方法很简单,在内核代码(文档)直接搜索broadcast_frames_received这样的数据名称即可,这些数据名称都来自内核定义,比如mvpp2中定义了上面的数据。一个实际的网卡接口可能有多种驱动,这个是存在的,因此输出的数据可能是不同驱动统计的数据,即来自于不同的硬件。

设置网卡参数

# Change generic options
ethtool [ FLAGS ] -s|--change DEVNAME   
[ speed %d ]
[ lanes %d ]
[ duplex half|full ]
[ port tp|aui|bnc|mii|fibre|da ]
[ mdix auto|on|off ]
[ autoneg on|off ]
[ advertise %x[/%x] | mode on|off ... [--] ]
[ phyad %d ]
[ xcvr internal|external ]
[ wol %d[/%d] | p|u|m|b|a|g|s|f|d... ]
[ sopass %x:%x:%x:%x:%x:%x ]
[ msglvl %d[/%d] | type on|off ... [--] ]


设置网卡流分类规则

展示流分类的规则命令如下:
# Show Rx network flow classification options or rules
ethtool [ FLAGS ] -n|-u|--show-nfc|--show-ntuple DEVNAME        
[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|tcp6|udp6|ah6|esp6|sctp6 [context %d] | rule %d ]

下面是设置的命名:
# Configure Rx network flow classification options or rules
ethtool [ FLAGS ] -N|-U|--config-nfc|--config-ntuple DEVNAME    
rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... [context %d] |
flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4|ip6|tcp6|udp6|ah6|esp6|sctp6
[ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]
[ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]
[ proto %d [m %x] ]
[ src-ip IP-ADDRESS [m IP-ADDRESS] ]
[ dst-ip IP-ADDRESS [m IP-ADDRESS] ]
[ tos %d [m %x] ]
[ tclass %d [m %x] ]
[ l4proto %d [m %x] ]
[ src-port %d [m %x] ]
[ dst-port %d [m %x] ]
[ spi %d [m %x] ]
[ vlan-etype %x [m %x] ]
[ vlan %x [m %x] ]
[ user-def %x [m %x] ]
[ dst-mac %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]
[ action %d ] | [ vf %d queue %d ]
[ context %d ]
[ loc %d]] |
delete %d

参数的详细解析请参考:ethtool(8) - Linux manual page (man7.org)

其他类命令

还有一些其他的命令如下:

执行网卡自身测试(需要网卡支持)
# Execute adapter self test
ethtool [ FLAGS ] -t|--test DEVNAME [ online | offline | external_lb ]

打印网卡转储数据(dump data)
# Get dump flag, data
ethtool [ FLAGS ] -w|--get-dump DEVNAME [ data FILENAME ]

# Set dump flag of the device
ethtool [ FLAGS ] -W|--set-dump DEVNAME
N

显示时钟采样信息
# Show time stamping capabilities
ethtool [ FLAGS ] -T|--show-time-stamping DEVNAME       

显示接收流的哈希间接表,设置RSS哈希散列,将网卡的包散射到不同的接收队列中。
# Show Rx flow hash indirection table and/or RSS hash key
ethtool [ FLAGS ] -x|--show-rxfh-indir|--show-rxfh DEVNAME [ context %d ]
# Set Rx flow hash indirection table and/or RSS hash key
ethtool [ FLAGS ] -X|--set-rxfh-indir|--rxfh DEVNAME    
[ context %d|new ]
[ equal N | weight W0 W1 ... | default ]
[ hkey %x:%x:%x:%x:%x:.... ]
[ hfunc FUNC ]
[ delete ]

写入固件文件到网卡的存储空间
# Flash firmware image from the specified file to a region on the device
ethtool [ FLAGS ] -f|--flash DEVNAME FILENAME [ REGION-NUMBER-TO-FLASH ]

查询网卡的通道数目(IRQ或者触发IRQ的某些集合)
# Query Channels
ethtool [ FLAGS ] -l|--show-channels DEVNAME    
# Set Channels
ethtool [ FLAGS ] -L|--set-channels DEVNAME     
   [ rx N ]
   [ tx N ]
   [ other N ]
   [ combined N ]

查询eeprom中的信息
# Query/Decode Module EEPROM information and optical diagnostics if available
ethtool [ FLAGS ] -m|--dump-module-eeprom|--module-info DEVNAME
[ raw on|off ]
[ hex on|off ]
[ offset N ]
[ length N ]
[ page N ]
[ bank N ]
[ i2c N ]

查询网卡设备的私有标志
# Query private flags
ethtool [ FLAGS ] --show-priv-flags DEVNAME     
# Set private flags
ethtool [ FLAGS ] --set-priv-flags DEVNAME FLAG on|off ...

查询设备是否支持Energy-Efficient Ethernet。
# Show EEE settings
ethtool [ FLAGS ] --show-eee DEVNAME
# Set EEE settings
ethtool [ FLAGS ] --set-eee DEVNAME     
[ eee on|off ]
[ advertise %x ]
[ tx-lpi on|off ]
[ tx-timer %d ]

查看网卡(物理层)可调整参数
# Set PHY tunable
ethtool [ FLAGS ] --set-phy-tunable DEVNAME     
[ downshift on|off [count N] ]
[ fast-link-down on|off [msecs N] ]
[ energy-detect-power-down on|off [msecs N] ]
# Get PHY tunable
ethtool [ FLAGS ] --get-phy-tunable DEVNAME     
[ downshift ]
[ fast-link-down ]
[ energy-detect-power-down ]
# Get tunable
ethtool [ FLAGS ] --get-tunable DEVNAME
[ rx-copybreak ]
[ tx-copybreak ]
[ pfc-precention-tout ]
# Set tunable
ethtool [ FLAGS ] --set-tunable DEVNAME
[ rx-copybreak N]
[ tx-copybreak N]
[ pfc-precention-tout N]

重置网卡设备的组件状态,可以指定固定的组件
# Reset components
ethtool [ FLAGS ] --reset DEVNAME       
[ flags %x ] [ mgmt ] [ mgmt-shared ] [ irq ]
[ irq-shared ] [ dma ] [ dma-shared ] [ filter ]
[ filter-shared ] [ offload ] [ offload-shared ]
[ mac ] [ mac-shared ] [ phy ] [ phy-shared ]
[ ram ] [ ram-shared ] [ ap ] [ ap-shared ]
[ dedicated ] [ all ]

查询网卡设备对转发错误校正的支持情况
# Show FEC settings
ethtool [ FLAGS ] --show-fec DEVNAME    
# Set FEC settings
ethtool [ FLAGS ] --set-fec DEVNAME [ encoding auto|off|rs|baser|llrs [...]]

执行有线电缆测试,需要网卡支持
# Perform a cable test
ethtool [ FLAGS ] --cable-test DEVNAME
# Print cable test time domain reflectrometery data
ethtool [ FLAGS ] --cable-test-tdr DEVNAME      
[ first N ]
[ last N ]
[ step N ]
[ pair N ]

显示隧道相关的信息
# Show NIC tunnel offload information
ethtool [ FLAGS ] --show-tunnels DEVNAME

显示收发器模组的参数(transceiver module)
ethtool --show-module devname
ethtool --set-module devname [power-mode-policy high|auto]

网卡工作原理1

1.网卡收包

网线上的packet首先被网卡获取,网卡会检查packet的CRC校验,保证完整性,然后将packet头去掉,得到frame。网卡会检查MAC包内的目的MAC地址,如果和本网卡的MAC地址不一样则丢弃(混杂模式除外)。

网卡将frame拷贝到网卡内部的FIFO缓冲区,触发硬件中断。(如有ring buffer的网卡,好像frame可以先存在ring buffer里再触发软件中断,ring buffer是网卡和驱动程序共享,是设备里的内存,但是对操作系统是可见的,因为看到linux内核源码里网卡驱动程序是使用kcalloc来分配的空间,所以ring buffer一般都有上限,另外这个ring buffer size,表示的应该是能存储的frame的个数,而不是字节大小。另外有些系统的 ethtool 命令 并不能改变ring parameters来设置ring buffer的大小,暂时不知道为什么,可能是驱动不支持。)

网卡驱动程序通过硬中断处理函数,构建sk_buff,把frame从网卡FIFO拷贝到内存skb中,接下来交给内核处理。(支持napi的网卡应该是直接放在ring buffer,不触发硬中断,直接使用软中断,拷贝ring buffer里的数据,直接输送给上层处理,每个网卡在一次软中断处理过程能处理weight个frame)

过程中,网卡芯片对frame进行了MAC过滤,以减小系统负荷(除开混杂模式)。

2.网卡发包

网卡驱动程序将IP包添加14字节的MAC头,构成frame(暂无CRC)。该Frame中含有发送端和接收端的MAC地址,由于是驱动程序创建MAC头,所以可以随便输入地址,也可以进行主机伪装。驱动程序将frame拷贝到网卡芯片内部的缓冲区,由网卡处理。

网卡芯片将未完全完成的frame(缺CRC)再次封装为可以发送的packet,也就是添加头部同步信息和CRC校验,然后丢到网线上,就完成一个IP报的发送了,所有接到网线上的网卡都可以看到该packet。

3.网卡中断处理函数

产生中断的每个设备都有一个相应的中断处理程序,是设备驱动程序的一部分。每个网卡都有一个中断处理程序,用于通知网卡该中断已经被接收了,以及把网卡缓冲区的数据包拷贝到内存中。

当网卡接收来自网络的数据包时,需要通知内核数据包到了。网卡立即发出中断。内核通过执行网卡已注册的中断处理函数来做出应答。中断处理程序开始执行,通知硬件,拷贝最新的网络数据包到内存,然后读取网卡更多的数据包。

这些都是重要、紧迫而又与硬件相关的工作。内核通常需要快速的拷贝网络数据包到系统内存,因为网卡上接收网络数据包的缓存大小固定,而且相比系统内存也要小得多。所以上述拷贝动作一旦被延迟,必然造成网卡FIFO缓存溢出 - 进入的数据包占满了网卡的缓存,后续的包只能被丢弃,这也应该就是ifconfig里的overrun的来源。

当网络数据包被拷贝到系统内存后,中断的任务算是完成了,这时它把控制权交还给被系统中断前运行的程序。

4.缓冲区访问

网卡的内核缓冲区,是在PC内存中,由内核控制,而网卡会有FIFO缓冲区,或者ring buffer,这应该将两者区分开。FIFO比较小,里面有数据便会尽量将数据存在内核缓冲中。

网卡中的缓冲区既不属于内核空间,也不属于用户空间。它属于硬件缓冲,允许网卡与操作系统之间有个缓冲;

内核缓冲区在内核空间,在内存中,用于内核程序,做为读自或写往硬件的数据缓冲区;

用户缓冲区在用户空间,在内存中,用于用户程序,做为读自或写往硬件的数据缓冲区;

另外,为了加快数据的交互,可以将内核缓冲区映射到用户空间,这样,内核程序和用户程序就可以同时访问这一区间了。

对于有ring buffer的网卡,ring buffer是由驱动与网卡共享的,所以内核可以直接访问ring buffer,一般拷贝frames的副本到自己的内核空间进行处理(deliver到上层协议,之后的一个个skb就是按skb的指针传递方式传递,直到用户获得数据,所以,对于ring buffer网卡,大量拷贝发生在frame从ring buffer传递到内核控制的计算机内存里)。

网卡工作原理2

1.网卡收包的基本过程

ethtool是一个非常复杂的工具,很难一次性全部了解,因此先要从基本的收包流程走起。

一般数据包接收有以下几个步骤:
网卡收到数据包,这是硬件外设主动收包,CPU无法感知。
将数据包从网卡硬件缓存转移到服务器内存中。
通知内核处理,也就是发出中断申请。
经过TCP/IP协议逐层处理。
应用程序通过read()从socket buffer读取数据。

整体大概如下图所示:


网卡收到包时,需要同步到内核中,这需要通过rx ring buffer,这是由NIC和驱动程序共享的一片区域,rx ring buffer 存储的并不是实际的 packet 数据,而是一个描述符,这个描述符指向了它真正的存储地址。


整体过程大概如上所示,如果驱动处理速度跟不上网卡收包速度,即来不及分配缓冲区并填入描述符,那么网卡只能丢弃新的数据包。

RX ring里面放着的是mbuf的描述符,即地址和大小等信息。

较新的网卡,无需再内部的FIFO队列(数据包级别)中暂时缓冲数据包,直接将数据包接收的每个字节通过DMA直接传输到目的内存上。

如果网卡产生丢包现象,可从以下地方查看:
使用ethtool -S dev_name查看统计数据,一般rx_fifo_errors表示网卡丢包,但也可能是其他字段,要根据具体情况确定。
在proc/net/dev中fifo字段增长,如果网卡驱动不由内核掌管,未必有统计值。
使用ifconfig命令,查看overruns统计数据,同样未必一定是准确的。

还可在/proc/net/softnet_stat里查看CPU软中断丢包的情况,


1).每一行表示每个cpu的softnat_data统计数据;

2).第1列表示该cpu收到的包个数;

3).第2列表示因softnet_data的输入队列满而丢弃的数据包个数(input_pkt_queue,队列长度最大值可通过 /proc/sys/net/core/netdev_max_backlog调整);

4).第3列表示软中断一次取走netdev_budget个数据包,或取数据包时间超过2ms的次数;

2.CPU中断响应

在网卡通过DMA将数据包传输到内存之后,需要通过(DMA传输完成)中断来告诉CPU此刻已经完成数据传输。

对于Linux系统,中断一般分为两种,硬中断和软中断:
硬中断:一般由硬件生成,中断处理程序只会处理关键性的、短时间内可以处理完的工作,剩余耗时较长工作,会放到中断之后,由软中断来完成。硬中断也被称为上半部分。

软中断: 一般由软件生成,往往是预先在代码里实现好的,不具有随机性。也被称为下半部分。

对于网卡收包来说,硬中断的中断处理程序一般由驱动程序提供,也可能完全屏蔽中断,从而采用轮询的模式收包。在此基础上,也有一种折中的方案,即中断+轮询,能避免一直轮询霸占CPU,也不会响应太多中断。

3.ifconfig相关参数解析

这里只介绍一些额外的信息:
Rx errors,总的收包错误数量,包括帧错误(校验,太长,同步等等),Ring buffer溢出, 网卡丢包,内存不足等等。
Rx dropped,数据包已经进入了 Ring Buffer,但是由于内存不够等系统原因,导致在拷贝到内存的过程中被丢弃。
Rx overruns,由于CPU无法及时的处理报文,导致Ring buffer被耗完,从而网卡直接丢包。

将 ethtool 设置永久保存

将 ethtool 设置永久保存在网络设备有两种方法,一种是写入网口配置文件中,一种是开机自启动脚本。

解决方法一: ethtool 设置可通过 /etc/sysconfig/network-scripts/ifcfg-ethX 文件保存,从而在设备下次启动时激活选项。
例如:ethtool -s eth0 speed 100 duplex full autoneg off

此指令将eth0设备设置为全双工自适应,速度为100Mbs。若要eth0启动时设置这些参数, 修改文件/etc/sysconfig/network-scripts/ifcfg-eth0 ,添加如下一行: ETHTOOL_OPTS="speed 100 duplex full autoneg off"

解决方法二: 将ethtool设置写入/etc/rc.d/rc.local之中。

优化 Linux 虚拟机网卡性能

在高并发应用场景下,Linux 虚拟机可能会出现丢包现象,可以通过调整网卡的 Buffer size 来缓解此问题。
使用 ethtool 来查看和修改 RX/TX 值来获取更好性能,以下为参考示例:

在 ethtool 配置文件中可以看到,RX/TX 值的单位是 section size:
#define NETVSC_SEND_SECTION_SIZE    6144
#define NETVSC_RECV_SECTION_SIZE    1728

查看当前网卡 RX/TX 参数:
# ethtool -g eth0
Ring parameters for eth0: Pre-set maximums: RX: 18811
RX Mini: 0
RX Jumbo: 0
TX: 2560
Current hardware settings: RX: 10486
RX Mini: 0
RX Jumbo: 0
TX: 192

重要

Pre-set maximums 中的 RX/TX 值为该网卡的 Buffer size 最大值;
Current hardware settings 中 RX/TX 值代表该网卡当前的 Buffer size 大小;
所以,设置的 Current hardware settings 的 RX/TX 值必须在 Pre-set maximums 的限制之内。

调整 RX/TX 参数:
# ethtool -G eth0 rx 18000 tx 2500

查看调整后的 RX/TX 参数:
# ethtool -g eth0
Ring parameters for eth0: Pre-set maximums: RX: 18811
RX Mini: 0
RX Jumbo: 0
TX: 2560
Current hardware settings: RX: 18000
RX Mini: 0
RX Jumbo: 0
TX: 2500

由于重启之后修改会失效,可以在 rc.local 中设置为开机自动运行修改命令,参考如下:
# chmod -x /etc/rc.d/rc.local

添加修改命令,并保存:
# vi /etc/rc.d/rc.local

#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.

touch /var/lock/subsys/local
ethtool -G eth0 rx 18000 tx 2500

重启并验证:
# ethtool -g eth0
Ring parameters for eth0: Pre-set maximums: RX: 18811
RX Mini: 0
RX Jumbo: 0
TX: 2560
Current hardware settings: RX: 18000
RX Mini: 0
RX Jumbo: 0
TX: 2500

解决网卡丢包严重一例

查看网卡时发现overruns值不断增加,学习了一下相关的知识。发现数值也在不停的增加。发现这些 errors, dropped, overruns 表示的含义还不大一样。

(1).RX errors
表示总的收包的错误数量,这包括 too-long-frames 错误,Ring Buffer 溢出错误,crc 校验错误,帧同步错误,fifo overruns 以及 missed pkg 等等。

(2).RX dropped
表示数据包已经进入了 Ring Buffer,但是由于内存不够等系统原因,导致在拷贝到内存的过程中被丢弃。

(3).RX overruns
表示了 fifo 的 overruns,这是由于 Ring Buffer(aka Driver Queue) 传输的 IO 大于 kernel 能够处理的 IO 导致的,而 Ring Buffer 则是指在发起 IRQ 请求之前的那块 buffer。很明显,overruns 的增大意味着数据包没到 Ring Buffer 就被网卡物理层给丢弃了,而 CPU 无法即使的处理中断是造成 Ring Buffer 满的原因之一,上面那台有问题的机器就是因为 interruprs 分布的不均匀(都压在 core0),没有做 affinity 而造成的丢包。

(4).RX frame
表示 misaligned 的 frames。

丢包排查
网卡工作在数据链路层,数据量链路层,会做一些校验,封装成帧。可以查看校验是否出错,确定传输是否存在问题。然后从软件层面,是否因为缓冲区太小丢包。

1.先查看硬件情况
一台机器经常收到丢包的报警,先看看最底层的有没有问题: (1).查看工作模式是否正常
# ethtool eth0 | egrep 'Speed|Duplex'
Speed: 1000Mb/s
Duplex: Full
 
(2).查看检验是否正常
# ethtool -S eth0 | grep crc
rx_crc_errors: 0
 
Speed,Duplex,CRC 之类的都没问题,基本可以排除物理层面的干扰。

2.通过 ifconfig 可以看到 overruns 是否一直增大

for i in `seq 1 100`; do ifconfig eth2 | grep RX | grep overruns; sleep 1; done

这里一直增加
RX packets:346547659 errors:0 dropped:0 overruns:35545 frame:0

3.查看buffer大小

可以通过ethtool来修改网卡的buffer size,首先要网卡支持,这里是INTEL的1000M网卡。
-g   –show-ringQueries the specified ethernet device for rx/tx ring parameter information.
-G   –set-ringChanges the rx/tx ring parameters of the specified ethernet device.

(1).查看当前网卡的buffer size情况
# ethtool -g eth0
Ring parameters for eth0: Pre-set maximums: RX: 4096
RX Mini: 0
RX Jumbo: 0
TX: 4096
Current hardware settings: RX: 256
RX Mini: 0
RX Jumbo: 0
TX: 256
 
4.修改buffer size大小
# ethtool -G eth0 rx 2048
# ethtool -G eth0 tx 2048
# ethtool -g eth0
Ring parameters for eth0: Pre-set maximums: RX: 4096
RX Mini: 0
RX Jumbo: 0
TX: 4096
Current hardware settings: RX: 2048
RX Mini: 0
RX Jumbo: 0
TX: 2048

字段解释(RX和TX的含义是类似的):
Pre-set maximums,这个是最大数目,实际上是配置大小或者初始化大小,只可以读。
Current hardware settings,这个是当前设置的数目,可以被ethtool工具修改。
RX/TX,接收发送缓冲区最大的可缓存描述符数量。
RX Mini,intel ixgel网卡的多收包队列之一,用于接收较小的数据包。
RX Jumbo,intel ixgel网卡的多收包队列之一,用于接收较大的数据包(MTU>1500)。

Mini-ring 和 Jumbo-ring不一定单独存在,因此不存在时其数据为0。

此外还有三个字段:
rx-buf-len,Rx-ring的buffer其大小。
cqe-size,完成事件队列的大小。
tx-push on/off,TX push是否应该使能。

ethtool源码的ethtool.h文件:

stats_block_coalesce_usecs,驱动在内存里统计数据的更新延迟(us),如果驱动不支持,应忽略该值。此值不能为0。
rate_sample_interval,多久做一次自适应合并包率采样,以秒为单位。这个参数指定多久进行一次自适应合并包速率的调整,采样的包速率值将和下面的pkt-rate-low和pkt-rate-high进行对比。此值不能为0。
pkt-rate-low,低速率包的判定阈值(按每秒计算)。
pkt-rate-high,高速率包的判定阈值(按每秒计算)。
rx-usecs(rx_coalesce_usecs),在一个报文达到后,延迟触发RX中断的时间(us)。
rx-frames(rx_max_coalesced_frames),在触发RX中断之前能接受的最大报文数目(Max num)。
rx-usecs-irq(rx_coalesce_usecs_irq),和rx-usecs相同,但只在中断正在被响应时才会生效。比如收到了一个报文,但此时RX中断服务例程正在执行,那么就会延迟指定微妙后触发RX中断。如果无RX中断服务例程在执行,那么就会直接触发RX中断。
rx-frames-irq(rx_max_coalesced_frames_irq),和rx-frames相同,但只在中断正在被响应时才会生效。
tx-usecs(tx_coalesce_usecs),在一个报文发送后,延迟触发TX中断的时间(us)。
tx-frames(tx_max_coalesced_frames),在触发TX中断之前能发送的最大报文数目(Max num)。
tx-usecs-irq(tx_coalesce_usecs_irq),和tx-usecs相同,但只在中断正在被响应时才会生效。
tx-frames-irq(tx_max_coalesced_frames_irq),和tx-frames相同,但只在中断正在被响应时才会生效。
rx-usecs-low(rx_coalesce_usecs_low),当报文接收速率低于pkt-rate-low时,一个报文到达后,延迟多少微妙(us)触发RX中断。
rx-frames-low(rx_max_coalesced_frames_low),当报文接收速率低于pkt-rate-low时,在触发RX中断之前能接收的最大报文数目(Max num)。
tx-usecs-low(tx_coalesce_usecs_low),当报文发送速率低于pkt-rate-low时,一个报文发送后,延迟多少微妙(us)触发TX中断。
tx-frames-low(tx_max_coalesced_frames_low),当报文发送速率低于pkt-rate-low时,在触发TX中断之前能发送的最大报文数目(Max num)。
rx-usecs-high(rx_coalesce_usecs_high),当报文接收速率高于pkt-rate-high时,一个报文到达后,延迟多少微妙(us)触发RX中断。
rx-frames-high(rx_max_coalesced_frames_high),当报文接收速率高于pkt-rate-high时,在触发RX中断之前能接收的最大报文数目(Max num)。
tx-usecs-high(tx_coalesce_usecs_high),当报文发送速率高于pkt-rate-high时,一个报文发送后,延迟多少微妙(us)触发TX中断。
tx-frames-high(tx_max_coalesced_frames_high),当报文发送速率高于pkt-rate-high时,在触发TX中断之前能发送的最大报文数目(Max num)。

最新版本:3.8
Pause advertising bits are now preserved when setting speed and duplex with autoneg on.
EEE parameters are no longer set if they are identical with the current parameters.

项目主页:http://www.kernel.org/pub/software/network/ethtool/