如何旁路内核协议栈

如何旁路内核协议栈

时间  2017-01-15

原文   http://blog.csdn.net/liukun321/article/details/54564798

此文转自:http://blog.csdn.net/wwh578867817/article/details/50139819

在前两篇文章中,我们讨论了如何每秒接收 1M UDP 数据包 以及 如何减少往返时间 。我们在 Linux 上做试验,因为它是一个性能非常好的通用操作系统。

不幸的是,对于一些更加专业的工作,Vanilla Linux(译者注:Linux 的内核版本,代号“香草”) 内核的网络速度是不够的。举个例子,在 CloudFlare,我们持续地处理洪水般的数据包。 Vanilla Linux 处理速度仅能达到约 1M pps (译者注:单位 packet per seconds),这在我们的工作环境下是不够的,特别是网卡有能力处理大量的数据包。现代 10Gbps 网卡的处理能力通常至少达到 10M pps 。

内核不给力

我们做一个小实验来说明修改 Linux 确实是有必要的。我们看看理想状态下内核能处理多少数据包。把数据包传递到用户空间的代价是高昂的,让我们尝试一下在网络驱动程序收到数据包后就立刻丢弃它们。据我所知,Linux 上不修改内核丢弃数据包最快的方法是在 PREROUTING iptables 上设置一些丢弃规则。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
$ sudo iptables -t raw -I PREROUTING -p udp --dport 4321 --dst 192.168.254.1 -j DROP $ sudo ethtool -X eth2 weight 1 $ watch ‘ethtool -S eth2|grep rx‘ rx_packets: 12.2m/s rx-0.rx_packets: 1.4m/s rx-1.rx_packets: 0/s ...

如上所示, Ethtool(译者注:Ethtool 是 Linux 下用于查询及设置网卡参数的命令)的统计显示,网卡能达到每秒接收 12M 数据包的速度。通过 ethtool -X 来操作网卡上的间接表,可以将所有的数据包引向 0 号 RX 队列。正如我们看到的,在一颗 CPU 上,内核处理队列的速度可以达到 1.4M pps。

在单核上能达到 1.4M pps 是一个相当不错的结果,但不幸的是协议栈却不能扩展。当数据包被分配到多核上,这个成绩会急剧下降。让我们看看把数据包分到 4 个 RX 队列的结果。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
$ sudo ethtool -X eth2 weight 1 1 1 1 $ watch ‘ethtool -S eth2|grep rx‘ rx_packets: 12.1m/s rx-0.rx_packets: 477.8k/s rx-1.rx_packets: 447.5k/s rx-2.rx_packets: 482.6k/s rx-3.rx_packets: 455.9k/s

此时每个核的处理速度是 480k pps。这是个糟糕的消息。即使乐观地假设增加多个核心不会进一步地造成性能的下降,处理数据包的核心也要多达 20 个才能达到线速度。所以内核是不起作用的。

内核旁路前来救驾

关于 Linux 内核网络性能的局限早已不是什么新鲜事了。在过去的几年中,人们多次尝试解决这个问题。最常用的技术包括创建特别的 API,来帮助高速环境下的硬件去接收数据包。不幸的是,这些技术总是在变动,至今没有出现一个被广泛采用的技术。

这里列出一些广为人知的内核旁路技术。

PACKET_MMAP

Packet mmap 是 Linux 上的API,用来实现数据包快速嗅探。然而它不是严格意义上的内核旁路技术,它是技术列表中的一个特例 —— 可以在 Vanilla 内核上使用。

PF_RING

PF_RING 是另一个已知的技术,用来提升捕获数据包的速度。不像 packet_mmap,PF_RING 不在内核主线中,需要一些特殊模块。通过 ZC 驱动和把模式设置成 transparent_mode = 2(译者注:是 PF_RING 的一种模式),只把数据包传递给 PF_RING 客户端,而不会经过内核网络协议栈。由于内核比较缓慢,这样可以确保高速运转。

Snabbswitch

Snabbswitch 是一个 Lua 网络框架,主要用来写 L2 应用。它可以完全接管一个网卡,并且在用户空间实现硬件驱动。它在一个 PCI 设备上实现了用户空间 IO(UIO),把设备寄存器映射到 sysfs 上(译者注:sysfs 是 Linux 内核中设计较新的一种虚拟的基于内存的文件系统) 。这样就可以非常快地操作,但是这意味着数据包完全跳过了内核网络协议栈。

DPDK

DPDK 是一个用 C 语言实现的网络框架,专门为 Intel 芯片创建。它本质上和 snabbswitch 类似,因为它也是一个基于UIO 的完整框架。

Netmap

Netmap 也是一个丰富的网络框架,但是和 UIO 技术不同,它是由几个内核模块来实现的。为了和网络硬件集成在一起,用户需要给内核网络驱动打补丁。增加复杂性的最大好处是有一个详细文档说明的、设备厂商无关的和清晰的 API

由于内核旁路技术的目的是不再让内核处理数据包,所以我们排除了 packet_mmap。因为它不能接收数据包 —— 它只是一个嗅探数据包的快速接口。同样,没有 ZC 模块的 PF_RING 也没有什么吸引力,因为它的主要目标是加速 libpcap(译者注:libpcap是unix/linux平台下的网络数据包捕获函数包,大多数网络监控软件都以它为基础)。

我们已经排除了两种技术,但很不幸的是,在余下的解决方案中,也没有我们能够使用的!

让我告诉你原因。为了用 剩下的技术 实现内核旁路技术:Snabbswitch、DPDK 和 netmap 会接管整个网卡,不允许网卡的任何流量经过内核。我们在 CloudFlare,根本不可能让一个分担负载的应用程序独占整个网卡。

话说回来,很多人使用上面的技术。在其他环境中占用一个网卡,来实现旁路也许是可以接受的。

Solarflare 上的 EF_VI

虽然上面列出的技术需要占用整个网卡,但还有其它的选择。

Solarflare 网卡支持 OpenOnload,一个神奇的网卡加速器。它通过如下方式来实现内核旁路,在用户空间实现网络协议栈,并使用 LD_PRELOAD 覆盖目标程序的网络系统调用。在底层访问网卡时依靠 “EF_VI” 库。这个库可以直接使用并且有很好的说明文档

EF_VI 作为一个专用库,仅能用在 Solarflare 网卡上,你可能想知道它实际是如何工作的。 EF_VI 是以一种非常聪明的方式重新使用网卡的通用功能。

在底层,每个 EF_VI 程序可以访问一条特定的 RX 队列,这条 RX 队列对内核不可见的。默认情况下,这个队列不接收数据,直到你创建了一个 EF_VI “过滤器”。这个过滤器只是一个隐藏的流控制规则。你用 ethtool -n 也看不到,但实际上这个规则已经存在网卡中了。对于 EF_VI 来说,除了分配 RX 队列并且管理流控制规则,剩下的任务就是提供一个API 让用户空间可以访问这个队列。

分叉驱动

虽然 EF_VI 是 Solarflare 所特有的,其他网卡还是可以复制这个技术。首先我们需要一个支持多队列的网卡,同时它还支持流控制和操作间接表。

有了这些功能,我们可以:

  • 正常启动网卡,让内核来管理一切。
  • 修改间接表以确保没有数据包流向任一 RX 队列。比如说我们选择
  • 16 号 RX 队列。
  • 通过流控制规则将一个特定的网络流引到 16号 RX 队列。

完成这些,剩下的步骤就是提供一个用户空间的 API ,从 16 号 RX 队列上接收数据包,并且不会影响其他任何队列。

这个想法在 DPDK 社区被称为“分叉驱动”。它们打算在 2014 年创建分叉驱动,不幸的是 这个补丁 还没进入内核的主线。

虚拟化方法

针对 intel 82599 还有另外一种选择。我们可以利用网卡上的虚拟化功能来实现内核旁路,而不需要通过分叉驱动程序。

首先我简单说下背景。有结果证明,在虚拟化世界中将数据包从主机传递到客户机,虚拟机通常是瓶颈。因此,这些年对虚拟化性能的需求与日俱增,通过软件模拟网络硬件的仿真技术成为了影响性能的主要障碍。

网卡厂商增加一些特性来加速虚拟客户端。其中一项虚拟化技术,要求网卡虚拟成多个 PCI 设备。虚拟客户端可以操作这些虚拟接口,无需与主机操作系统进行任何合作。我演示一下它是如何工作的。举个例子,这是我本机上的 82599 网卡。这个“真实的”设备被称为 PF(物理功能)接口:

  • 1
  • 2
  • 1
  • 2
$ lspci 04:00.1 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01)

我们要求这个设备创建一个 VF(虚拟功能)设备:

  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
$ echo 1 > /sys/class/net/eth3/device/sriov_numvfs $ lspci 04:00.1 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01) 04:10.1 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)

比如说一个 KVM 客户端很容易使用这个假的 PCI 设备。同时,我们还是能够使用主机环境。要做到这些仅需要加载 “ixgbevf” 内核模块,之后会出现另一个 “ethX” 接口。

你或许想知道内核旁路技术干了什么。内核没有利用“ixgbevf”设备正常联网,我们可以把它专门用在内核旁路上。这样看起来可以在 “ixgbevf” 设备运行 DPDK

概括来说:这个想法可以让 PF 设备正常处理内核工作,而 VF 接口专门用在内核旁路技术上。由于 VF 是专用的,所以我们可以运行“接管整个网卡”的技术。

这听起来似乎不错,实际上却没那么简单。首先,只有 DPDK 支持“ixgbevf”设备,netmap,snabbswtich 和 PF_RING 是不支持的。默认情况下, VF 接口不能接收任何数据包。若通过 PF 发送数据给 VF ,你需要给 ixgbe 打上这个补丁。有了它,你可以对 VF 进行寻址,即在ethtool中对“活动”“队列号的高位进行编码。

  • 1
  • 1
$ ethtool -N eth3 flow-type tcp4 dst-ip 192.168.254.30 dst-port 80 action 4294967296

最后一个障碍出现了,在 82599 芯片上启用 VF 功能,RSS 组的最大规模变小了(译者注:Really Simple Syndication,简易信息聚合)。没有虚拟化时,82599 可以在 16 个 CPU 核上进行 RSS 。但随着 VF 的启用,这个数量却变成了 4。如果 PF 上的流量比较低,只使用 4 个核来发布可能还好。不幸的是,我们在 Cloudflare 需要处理大规模的 RSS 组。

结束语

完成内核旁路技术没有那么简单。虽然存在很多开源的技术,但它们看起来都需要一块专用的的网卡。这里我们展示了 3 个可以选择的框架:

  • 类似 EF_VI, 隐藏 RX 队列
  • DPDK 分叉驱动
  • VF 技术

不幸的是,在我们的环境下,这么多技术中能起作用的似乎只有 EF_VI。我们祈祷开源的内核旁路 API 赶紧出现,唯一的要求是不需要一块专用的网卡。

相关文章

相关标签/搜索

内核协议栈

内核协议

linux内核协议栈

内置协议栈

zigbee协议栈

lwip协议栈

PPP协议栈

zstack协议栈

协议栈

ip 协议栈

内核协议栈内核协议栈

内核协议栈

linux内核协议栈

linux内核协议栈

linux内核协议

协议栈

UIP协议栈

SIP协议栈

BLE协议栈

内置协议栈cc2530协议栈

cc2650SDK协议栈

mqtt协议栈

MQTT协议栈

lorawan协议栈

cc2541 协议栈

mqtt 协议栈

如何理解BLE协议栈内置协议栈 外置协议栈 区别

原文地址:https://www.cnblogs.com/zafu/p/9003392.html

时间: 2024-11-12 13:11:04

如何旁路内核协议栈的相关文章

Linux内核协议栈的socket查找缓存路由机制

是查路由表快呢?还是查socket哈希表快?这不是问题的根本.问题的根本是怎么有效利用这两者,让两者成为合作者而不是竞争者.这是怎么回事?       我们知道,如果一个数据包要到达本地,那么它要经过两次查找过程(暂时不考虑conntrack):IP层查找路由和传输层查找socket.怎么合并这两者.       Linux内核协议栈采用了一种办法:在socket中增加一个dst字段作为缓存路由的手段,skb在查找路由之前首先查找socket,找到的话,就将缓存的dst设置到skb,接下来在查找

Linux2.6内核协议栈系列--TCP协议2.接收

1.排队机制 接收输入TCP报文时,有三个队列: ● 待处理队列 ● 预排队队列 ● 接收队列 接收队列包含了处理过的TCP数据段,也就是说,去除了全部的协议头,正准备将数据复制到用户应用程序.接收队列包含了所有按顺序接收的数据段,在其他两个队列中的TCP数据段则需要进一步处理. TCP报文首先由tcp_v4_rcv()进行处理.该函数要决定是否需要处理报文或者在待处理队列和预排队队列中排队. /* 传输层报文处理入口 */ int tcp_v4_rcv(struct sk_buff *skb)

Linux2.6内核协议栈系列--TCP协议1.发送

在介绍tcp发送函数之前得先介绍很关键的一个结构sk_buff,在linux中,sk_buff结构代表了一个报文: 然后见发送函数源码,这里不关注硬件支持的分散-聚集: /* sendmsg系统调用在TCP层的实现 */ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t size) { struct iovec *iov; struct tcp_sock *tp = tcp_sk(sk)

Linux内核协议栈 NAT性能优化之FAST NAT

各位看官非常对不起,本文是用因为写的,如果多有不便敬请见谅 代码是在商业公司编写的,在商业产品中也不能开源,再次抱歉 This presentation will highlight our efforts on optimizing the Linux TCP/IP stack for providing networking in an OpenStack environment, as deployed at our industrial customers. Our primary go

linux 内核网络协议栈阅读理解--带详尽注释以及相关流程调用注释,附 github 注释后源码

linux 内核网络协议栈阅读理解--带详尽注释以及相关流程调用注释,对理解内核协议栈源码很有帮助 对理解阅读 linux 协议栈源码很用帮助 github 地址: https://github.com/y123456yz/Reading-and-comprehense-linux-Kernel-network-protocol-stack

linux内核网络协议栈架构分析,全流程分析-干货

https://download.csdn.net/download/wuhuacai/10157233 https://blog.csdn.net/zxorange321/article/details/75676063 LINUX内核协议栈分析 目  录 1      说明...4 2      TCP协议...4 2.1       分层...4 2.2       TCP/IP的分层...5 2.3       互联网的地址...6 2.4       封装...7 2.5       

关于用户态协议栈的思考

一直以来我一直以为操作系统内核是高大上的东西,但是实际上用户态的应用才是!上周的一次技术交流中,一家网络加速卡厂商声称他们的协议栈是用户态的协议栈,用来提高性能,我对其产品直接就泄了气,然而会后,我查阅了相关的资料,找到一篇文章<千万并发的秘密-内核是问题的根本>,写出了我的心声,原来我一直都是这么认为的,只是一直都不敢承认罢了,为何不敢承认,那是因为我酷爱内核.我对那家厂商泄气表达了我深深的虚伪,内在的分裂!       文中说"我们学的是Unix而不是网络编程",对&l

Linux内核中网络数据包的接收-第一部分 概念和框架

与网络数据包的发送不同,网络收包是异步的的,因为你不确定谁会在什么时候突然发一个网络包给你,因此这个网络收包逻辑其实包含两件事:1.数据包到来后的通知2.收到通知并从数据包中获取数据这两件事发生在协议栈的两端,即网卡/协议栈边界以及协议栈/应用边界:网卡/协议栈边界:网卡通知数据包到来,中断协议栈收包:协议栈栈/应用边界:协议栈将数据包填充socket队列,通知应用程序有数据可读,应用程序负责接收数据.本文就来介绍一下关于这两个边界的这两件事是怎么一个细节,关乎网卡中断,NAPI,网卡poll,

C1000k 新思路:用户态 TCP/IP 协议栈

C1000k 新思路:用户态 TCP/IP 协议栈 如今的server支撑上百万个并发 TCP 连接已经不是新闻(余锋2010年的演讲,ideawu 的 iComet 开源项目,WhatsApp 做到了 2.5M).实现 C1000k 的常规做法是调整内核參数,提高文件数,降低每一个连接的内存消耗(參考 ideawu 的博客). 在今年的 BSDCan2014 会议上, Patrick Kelsey 介绍了把 FreeBSD 9.x 的 TCP/IP 协议栈移植到了用户态(slides, git