linux网络发包性能优化

1. 网络发包性能

对于网络的行为,可以简单划分为 3 条路径:1) 发送路径,2) 转发路径,3) 接收路径,而网络性能的优化则可基于这 3 条路径来考虑。
由于数据包的转发一般是具备路由功能的设备所关注,所以我们只关注发送路径和接受路径。
其中的 NAPI 本质上是接收路径上的优化,但因为它在 Linux 的内核出现时间较早,而它也是后续出现的各种优化方法的基础,所以将其单独分析。

1.1 NAPI

NAPI 的核心在于:在一个繁忙网络,每次有网络数据包到达时,不需要都引发中断,因为高频率的中断可能会影响系统的整体效率。
假象一个场景,我们此时使用标准的 100M 网卡,可能实际达到的接收速率为 80MBits/s,而此时数据包平均长度为 1500Bytes,则每秒产生的中断数目为:
80M bits/s / (8 Bits/Byte * 1500 Byte) = 6667 个中断 /s
每秒 6667 个中断,对于系统是个很大的压力,此时其实可以转为使用轮询 (polling) 来处理,而不是中断。
但轮询在网络流量较小的时没有效率,因此低流量时,基于中断的方式则比较合适,这就是 NAPI 出现的原因:在低流量时候使用中断接收数据包,而在高流量时候则使用基于轮询的方式接收。

1.2 发送路径上的优化

TSO (TCP Segmentation Offload)
我们知道通常以太网的MTU是1500,除去TCP/IP的包头,TCP的MSS (Max Segment Size)大小是1460,通常情况下协议栈会对超过1460的TCP payload进行segmentation,保证生成的IP包不超过MTU的大小。
但是对于支持TSO/GSO的网卡而言,就没这个必要了,我们可以把最多64K大小的TCP payload直接往下传给协议栈,此时IP层也不会进行segmentation,一直会传给网卡驱动,支持TSO/GSO的网卡会自己生成TCP/IP包头和帧头,这样可以offload很多协议栈上的内存操作,checksum计算等原本靠CPU来做的工作都移给了网卡
TSO (TCP Segmentation Offload) 是一种利用网卡分割大数据包,减小 CPU 负荷的一种技术,也被叫做 LSO (Large segment offload) ,如果数据包的类型只能是 TCP,则被称之为 TSO。
对于硬件,具体说来,硬件能够对大的数据包进行分片,分片之后,还要能够对每个分片附着相关的头部。
GSO (Generic Segmentation Offload)
TSO 是使得网络协议栈能够将大块 buffer 推送至网卡,然后网卡执行分片工作,这样减轻了 CPU 的负荷,但 TSO 需要硬件来实现分片功能;
而性能上的提高,主要是因为延缓分片而减轻了 CPU 的负载,因此,可以考虑将 TSO 技术一般化,因为其本质实际是延缓分片,这种技术,在 Linux 中被叫做 GSO(Generic Segmentation Offload),它比 TSO 更通用,原因在于它不需要硬件的支持分片就可使用。
对于支持 TSO 功能的硬件,则先经过 GSO 功能,然后使用网卡的硬件分片能力执行分片;而对于不支持 TSO 功能的网卡,将分片的执行,放在了将数据推送的网卡的前一刻,也就是在调用驱动的 xmit 函数前。
为什么TCP/IP包长会大于MTU
tcpdump抓包的数据是在包送到网卡之前的信息,所以在tcpdump里面的包大小可能会大于MTU。
但是一旦数据进入网卡后的处理信息在tcpdump里面是反应不了的,因此数据包被分片这样的消息自然是没办法知道,只有在目标方才能反应出具体的分包细节。
所以这次发现tcp/ip包长大于MTU其实算是个“假象”,因为在真正的链路层上传输数据时是不会大于MTU的。

1.3 接收路径上的优化

LRO (Large Receive Offload)
Linux 在 2.6.24 中加入了支持 IPv4 TCP 协议的 LRO (Large Receive Offload) ,它通过将多个 TCP 数据聚合在一个 skb 结构,在稍后的某个时刻作为一个大数据包交付给上层的网络协议栈,以减少上层协议栈处理 skb 的开销,提高系统接收 TCP 数据包的能力。
当然,这一切都需要网卡驱动程序支持。
合并了多个 skb 的超级 skb,能够一次性通过网络协议栈,而不是多次,这对 CPU 负荷的减轻是显然的。

GRO (Generic Receive Offload)
前面的 LRO 的核心在于:在接收路径上,将多个数据包聚合成一个大的数据包,然后传递给网络协议栈处理,但 LRO 的实现中存在一些瑕疵:

•   数据包合并可能会破坏一些状态 
•   数据包合并条件过于宽泛,导致某些情况下本来需要区分的数据包也被合并了,这对于路由器是不可接收的 
•   在虚拟化条件下,需要使用桥接功能,但 LRO 使得桥接功能无法使用 
•   实现中,只支持 IPv4 的 TCP 协议

而解决这些问题的办法就是新提出的 GRO(Generic Receive Offload)。首先,GRO 的合并条件更加的严格和灵活,并且在设计时,就考虑支持所有的传输协议,因此,后续的驱动,都应该使用 GRO 的接口,而不是 LRO,内核可能在所有先有驱动迁移到 GRO 接口之后将 LRO 从内核中移除。
而 Linux 网络子系统的维护者 David S. Miller 就明确指出,现在的网卡驱动,有 2 个功能需要使用:
一是使用 NAPI 接口以使得中断缓和 (interrupt mitigation) ,以及简单的互斥.
二是使用 GRO 的 NAPI 接口去传递数据包给网路协议栈。

2. TCP/IP网络栈

参考:http://blog.jobbole.com/86656/(这篇文章讲解得很清晰)

2.1 发送数据

最终的数据包会通过dev_queue_xmit函数完成传输。首先,数据包通过排队规则(译注:qdisc,上篇文章简单介绍过)传递。如果使用了默认的排队规则并且队列是空的,那么会跳过队列而直接调用sch_direct_xmit把数据包发送到驱动。dev_hard_start_xmit会调用实际的驱动程序。在调用驱动之前,设备的发送(译注:TX,transmit)被锁定,防止多个线程同时使用设备。由于内核锁定了设备的发送,驱动发送数据相关的代码就不需要额外的锁了。
ndo_start_xmit函数会调用驱动的代码。在这之前,你会看到ptype_all和dev_queue_xmit_nit。ptype_all是个包含了一些模块的列表(比如数据包捕获)。如果捕获程序正在运行,数据包会被ptype_all拷贝到其它程序中。因此,tcpdump中显示的都是发送给驱动的数据包。当使用了校验和卸载(checksum offload)或TSO(TCP Segment Offload)这些技术时,网卡(NIC)会操作数据包,所以tcpdump得到的数据包和实际发送到网络的数据包有可能不一致。在结束了数据包传输以后,驱动中断处理程序会返回发送了的sk_buff。

2.2 接收数据

一般来说,接收数据的执行路径是接收一个数据包并把数据加入到socket的接收缓冲区。
在执行了驱动中断处理程序之后,首先执行的是napi poll处理程序。
驱动接收到的数据包会发送给注册到ptype_all列表的那些模块,数据包在这里被捕获。
之后,根据数据包的类型,不同数据包会被传输到相应的上层。

3. 实验

网卡驱动调试方法

printk
这是驱动开发中最朴实无华,同时也是最常用和有效的手段。
用法如下:
printk(KERN_ALERT “wakeup by signal in process %d\n”, current->pid);
printk的功能与我们经常在应用程序中使用的printf是一样的,不同之处在于printk可以在打印字符串前面加上内核定义的宏,例如上面例子中的KERN_ALERT(注意:宏与字符串之间没有逗号)。

#define KERN_EMERG "<0>"
#define KERN_ALERT "<1>"
#define KERN_CRIT "<2>"
#define KERN_ERR "<3>"
#define KERN_WARNING "<4>"
#define KERN_NOTICE "<5>"
#define KERN_INFO "<6>"
#define KERN_DEBUG "<7>"
#define DEFAULT_CONSOLE_LOGLEVEL 7

这个宏是用来定义需要打印的字符串的级别。值越小,级别越高。
内核中有个参数用来控制是否将printk打印的字符串输出到控制台(屏幕或者/sys/log/syslog日志文件)

# cat /proc/sys/kernel/printk
6       4       1       7

第一个6表示级别高于(小于)6的消息才会被输出到控制台,
第二个4表示如果调用printk时没有指定消息级别(宏)则消息的级别为4,
第三个1表示接受的最高(最小)级别是1,
第四个7表示系统启动时第一个6原来的初值是7。
因此,如果你发现在控制台上看不到你程序中某些printk的输出,请使用echo 8 > /proc/sys/kernel/printk来解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值