阅读 netmap: a novel framework for fast packet I/O 文章总结
Abstract and Introduction
-
netmap:一个新型的框架,使得现在的操作系统可以在不需要特定硬件或针对应用进行改变的前提下,每秒钟通过1..10 Gbit/s的link处理百万级的packet。
-
减少或移除了三处packet处理过程中的cost:
- 每个packet的动态内存分配——通过预分配资源进行处理
- 系统调用的开销——摊销到large batches上
- 内存的备份——在kernel与userspace中共享buffer与metadata,同时仍保护了到device register和其他kernel memory areas的access。
-
主要贡献:
- performance超过了大部分的previous work
- 提供了一个architecture,在不使用特定硬件的条件下,紧密地整合了现有的操作系统primitives,且容易使用与维护。
-
performace具体性能:
- 基于FreeBSD,Linux和几个1Gbit/s 10Gbit/s的网络适配器实现
- 一个900MHz的single core接受发送速率可以达到14.88Mpps,超过了传统API的20倍。在使用了libpcap库(libpcap is a system-independent interface for user-level packet capture. )的情况下,仍能加速五倍以上。
- 在wire与userspace应用中传递一个packet只需要低于70个CPU clock cycles。
-
容易使用与维护的具体表现:
- 用户很难crash这个系统,因为设备的registers和关键的kernel memory区域不会暴露给用户,且用户无法在kernel中插入伪造的memory指针。
- netmap使用了一个极其简单的数据模型,使其可以适用于zero-copy的packet传递。
- netmap支持multi-queue的适配器。
- netmap使用了标准的系统调用。
以上几点使得netmap可以很容易地将现有应用转移到新的mechanism上,也可以很容易地通过有效地使用netmap API来实现新的应用。
-
为了提高性能,其他系统进行的处理:
- 完全在kernel中运行
- 绕开设备驱动,通过将NIC(网络适配器)的数据结构完全暴露给用户空间的应用,来堆放整个网络。
这些系统的缺陷:
- 依赖于特定的硬件特征
- 指向硬件的access不受保护
- 与现有的OS primitives整合得不好
Background
主要阐述了通用的OS的network stack组织结构,并展示了不同stages中的processing costs。
-
NIC数据结构与操作
NIC:通过buffer descriptors中的circular queues (rings) 管理packets的输入输出。
- 接收时:输入的packets被存储在下一个可使用的buffer中,length/status信息被写回到slot中。通过中断来告知CPU这些events。
- 传递时:将请求写入到NIC的register中,然后开始发送在TX(Transmit Traffic) ring中被标记为available的packets。
- 问题:高packet传输率时,中断处理比较昂贵,可能导致receive livelock,可能不能到达一定的装载量(load)。
- 解决方法:Polling device drivers,Hardware interrupt mitigation
-
Kernel与用户API
- OS中会保存一个NIC数据结构的影备份(见Figure1中的mbufs),其中存储着背个packet的元数据:size, source, destination interface, attributes, 标记NIC与OS应如何处理该buffer的flags。
- Driver/OS:设备驱动与OS间的API会希望subsystems可以保存packets来进行延迟处理,因此buffer和元数据需要被备份及reference-counted,这个处理则会导致运行时产生很大的overhead。API的通信,buffer chain的分配/管理/navigating也很影响性能。
- Raw packet I/O:为用户程序读/写raw packet的标准API, 每个packet至少需要一次kernel与user space间的memory copy及一个系统调用。
-
Case Study: FreeBSD sendto()
- time: return point在函数起点时的平均时间。
- delta:相邻row间的时间差。
- 代价昂贵的层:系统调用(无法避免);初始mbuf的构建/数据拷贝;route/header/MAC header的建立;将mbuf与元数据转化为NIC形式。
Related Work
-
Socket APIs —— BPF(Berkeley Packet Filter)
- BPF接入网络设备驱动的数据路径,将每一个需要发送或接收的packet的备份发给一个文件描述符,用户空间便可对该描述符进行读和写。
- BPF可与系统中常规的traffic共存,但BPF clients会杂乱放置card,增加传入host stack的traffic数量。
-
Packet filter hooks —— Netgraph (FreeBSD), Netfilter (Linux), Ndis Miniport drivers (Windows)
- 均为in-kernel的机制,使得可以不复制packet,而是将应用插入到packet的处理链中。
- Direct buffer access
- Kernel-mode Click, 不在数据传递时进行备份,而是直接在kernel中运行应用。但约束很多且很fragile。
- PF_RING / PACKET_MMAP, 开放一个包含了很多预分配packet buffer的共享内存区域给用户空间。其中,kernel负责备份sk_buffs与共享buffer间的数据,使得将系统调用的cost摊销到packets中,但仍有数据备份与sk_buff管理的overhead。
- UIO-IXGBE / PF_RING_DNA / Intel’s DPDK / SolarFlare’s OpenOnload, 在用户空间运行full stack直到NIC的access。这种方法需要常规的设备驱动,且由于NIC的DMA引擎可写到任意的内存地址,会导致一定的risk。
- NetChannel, 与Netmap有些类似,都删除了sk_bufs,避免了在中断handlers中的packet处理,将buffers map到了用户空间,且在用户空间中使用了合适的库来实现整个协议的处理。
- PSIOE (PacketShader I/O engine), 也与Netmap类似,使用了常规的设备驱动,使用一个较简单的API代替了基于sk_buff的API,且对buffer进行了预分配。使用常规的ioctl()来同步kernel和用户空间的应用。且在kernel与应用中有共享空间,kernel管理共享内存与packet buffer间的数据备份。但PSIOE只支持特定的NIC,且不支持select() / poll(),在应用调用新的API时也需要其进行一定的改变。
- Hardware solutions
有一些硬件会专门为了支持高速packet捕捉或generation而进行特定的设计,比如timestamping, filtering, forwarding。比如DAG cards, NetFPGA。 - Unrelated work
- Netmap: a framework to reduce the cost of moving traffic between the hardware and the host stack.
- TCP acceleration: 如hardware checksumming, encryption, 减少了host stack中的处理,但没有强调其与设备间的交流。
- Virtualization: 如支持多个hardware queues, 将traffic赋予特定的queues/虚拟机。
Netmap
-
Netmap实现的几种技术:
- 一种轻量的元数据表示法,紧凑,易使用,隐藏了device-specific features。每一次系统调用咳咳处理大量packet,分摊了开销。
- 线性的,固定大小的packet buffer。在设备打开时就进行了预分配,因此节省了每个packet分配与重分配的开销。
- 允许应用直接,受到保护地访问packet buffer,移除了数据备份的开销。也支持接口间的packet零备份传输。
- 支持useful hardware features。
-
netmap架构
NIC用于在network与memory间快速地移动数据,OS用于加强保护并提供对同步的支持。其中NIC与host stack部分不链接。使用传统的OS primitive来进行同步。
-
数据结构
-
主要作用与特点:
- 减少或分摊每个packet的overhead
- 使数据可以在接口间有效地进行转运
- 使NIC与host stack间可以有效地交流
- 支持multi-queue的适配器和多核的系统。
-
主要包括三种类型的用户可见object,均被kernel分配放置在同一块内存区域,被所有用户进程共享。便于支持接口间零备份的转运。由于共享内存被进程和kernel线程map到了不同的虚拟地址空间,因此对该区域的内存引用必须使用相对路径,在实现时可以在parent与child间使用偏移量offset进行表示。
- packet buffer: 大小是固定的(当前使用的2Kbytes),被NIC与用户进程共享。 每一个buffer有一个自己的index,被用户进程或kernel用于转化为虚拟地址,被NIC用于转化为物理地址。当接口变为netmap模式时buffer会被预分配,因此不需要network I/O来分配。每一个buffer会被对应到一个netmap ring与相应的hardware ring。
-
netmap ring: NIC中独立于设备的一个数据备份。其中的数据包括:
- ring_size: 此ring中包含的slot数目。
- cur: ring中当前读或写的位置。
- avail: 可使用的buffer 的数目。
- buf_ofs: 此ring与packet buffer数据开始位置的偏移量。
- slots[]: 每个slot中包含对应packet buffer的index,该packet的长度和一些用于请求对buffer进行特殊操作的flags。
- netmap_if: 有关接口的一些只读信息,例如ring的数目,netmap_if间的内存偏移数组,每个与接口有关的netmap ring等。
-
数据访问与所有权
- netmap数据结构虽然被kernel与userspace共享,但不同数据区域的所有权被很好地定义,因此不会发生冲突。
- 除了系统调用的时候, netmap_ring一直归属于userspace的应用。中断处理或其他的kernel线程都无法接触netmap ring。
- cur与cur+avail-1中的packet buffer都归属于userspace应用,而其他的buffer则归属于kernel(NIC)。两者之间的分界线在系统调用时进行更新。
-
主要作用与特点:
-
netmap API
-
将接口转为netmap mode的流程
- 打开特定的设备 /dev/netmap
- 发送一个 ioctl(.., NIOCREG, arg) 命令给file descriptor。其中参数包含了接口名称及想通过该file descriptor控制哪些ring的说明。成功后返回共享内存区域的大小及netmap_if的偏移量。
- file descriptor发出 mmap() 命令开放内存给进程的地址空间。完成file descriptor与某个接口及其ring的连接。
- 发送:从slot cur开始,发送 ioctl(.., NIOCTXSYNC) 命令,告诉OS有新的packets想发送。然后系统调用将信息传给kernel,kernel更新netmap ring中的avail区域。
- 接收:发送 ioctl(.., NIOCRXSYNC) 命令,询问OS有多少packet可读,然后从netmap ring中的slot中读取packet的长度和有效载荷。
-
该流程优点:
- non blocking
- 无数据备份
- 可同时处理多个packet
- 该流程中kernel部分主要的作用
工作量很少,不易引起系统崩溃。- 验证cur/avail区域及slots所包含的内容
- 同步netmap与hardware ring间slots的内容,给NIC发送命令告知有新的packets要发送或有新的可使用的buffer以供接收。
- 更新netmap ring中的avail区域。
- Blocking primitives
通过 select() 和 poll() 系统调用可以 block I/O。可以将netmap file descriptor传递给这些函数,当avail > 0时进行报告并调用。 - Multi-queue接口
面向多个ring pair时,file descriptor会进入两种模式之一:- default mode: file descriptor控制所有ring,让kernel检查任意ring的可使用buffer。
- alternate mode: 每个file descriptor对应一个 TX/RX ring pair。避免冲突或同步。
-
-
与host stack交互
即使处于netmap模式,OS中的network stack也会控制这些接口,产生一些traffic。这些traffic会使用一些额外的netmap ring处理。NIOCTXSYNC命令将buffer放入mbufs,然后发送给host stack。来自host stack的packet会进入“host stack”netmap ring,使用NIOCRXSYNC命令使其对netmap client available。然后netmap client需要保证这些pacekts在ring与NIC中进行传递。这个机制也可用于实现firewalls, traffic shapers, NAT boxes等等。 -
安全性考虑
使用netmap的进程,即使进行了误操作也不会引起kernel的crash。这是因为共享内存区域不包括非常重要的部分,且buffer的indexed和lengths都是经过kernel的验证才会被使用。然而进程误操作可能会损坏netmap rings或packet buffers。未来工作会对此进行考虑。 -
零备份的packet转运
由于所有接口共享同一片内存区域,因此想要实现零备份的packet转运,只需交换输入接口接收slot与输出接口传递slot的buffer indexes,然后更新长度与flags flelds便可。也避免了内存的分配问题。 -
libpcap兼容性
- 问题:如果没有应用需要某个API则这个API便没有了价值,以及如何采用现有的code给新的API。
- 解决方法:在netmap上写一个map libpcap调用与netmap调用的小型库。由于netmap只使用了标准的同步primitives,因此只需实现将 read/write函数map到相应netmap调用就行了。非常的简单。
-
具体实现内容
- 系统调用与驱动支持实现代码(2000行);定义netmap clients中结构/原型/宏命令的C头文件(200行)。
- 为了使设备驱动只需进行很小的改动,大部分的函数使用公共代码进行的实现(500行,一般设备驱动都需4k到10k行)。每个驱动只需实现两个函数:
- reinitialize netmap模式中的rings
- 将设备驱动locks输出为公共代码
- 使设备驱动大部分的工作都在实行系统调用时,在用户空间的进程中执行。这样做的优点:
- 提升了cache locality
- 简化了资源管理
- 提高了系统的可控性和鲁棒性
- 当avail > 0而执行系统调用时,不会回收再利用已经被转运的buffers,或者寻找更多的incoming packets。这使得应用不必给每一个packet都执行一次系统调用。
- 即使POLLOUT命令没有特殊标明,也会将任何等待转运的packets push out。减少了系统调用。
- poll() 返回之前在netmap ring中更新一个时间戳。减少了系统调用。
Performance分析
-
度量方式
主要测量在应用和network card间传输packets时CPU的costs。主要分为两部分:- Per-byte costs: 数据在NIC buffer中输入输出时CPU循环的消耗。由于netmap将NIC buffers开放给应用,因此这部分消耗为0。而其他API,如socket API大约在每byte 0.25~2 clock cycles。
-
Per-packet costs:
除了第一项,其他都可以被移除或分摊在多个packets中。- CPU必须要为每个packet更新NIC ring中的slot。
- 内存分配
- 系统调用
- program the NIC’s registers
- 更新statistics
- 最大的挑战就是传输多个最小的packets。因此做实验时选择的64 byte packets。同时为了减少应用的costs,测试时选择两个非常简单的程序:
- 不断流出预生成packets的packet生成器
- 只计算接受packets数目的packet接收器
-
测试设备
- i7-870 4-core CPU at 2.93 GHz
- memory running at 1.33 GHz
- a dual port 10 Gbit/s card based on Intel 82599 NIC
- FreeBSD HEAD/amd64 as of April 2012.
-
传输速度 VS clock rate
一个core在900MHz时会达到最大速度。
-
传输速度 VS packet size
之前实验都是用的最小packets,现在验证pakcet大小对传输速度的影响。可以看出transmit速度与size成反比,而receive速度只在64 byte时达到最大,调查显示这是因为NIC或I/O bridge发出的read-modify-write cycles不是full cache line。
-
传输速度 VS batch size
多个batches可以提高系统的throughput,这是因为它可将系统调用和其他昂贵的操作cost进行摊销。图中可以看出batch size为1时,throughput为2.45 Mpps (408 ns/pkt),batch size为8时可达到14.88 Mpps,而标准的FreeBSD poll() 大约在250ns。
-
Packet forwarding performance
通过packet forwarding来去除其他影响,测试netmap API的速度。- 实验说明:
- netmap-fwd: 使用零备份技术实现的接口间传递packets的简单应用。
- netmap-fwd + pcap: 与netmap-fwd相同,但没有使用零备份,而是用libpcap emulation。
- click-fwd: 使用的Click结构加上系统的libpcap,以及netmap上的libpcap emulation库。Click结构是:
- FromDevice(ix0) -> Queue -> ToDevice(ix1)
- FromDevice(ix1) -> Queue -> ToDevice(ix0)
- click-etherswitch: 与click-fwd相同,但用一个EtherSwitch取代了两个queue。
- openvswitch: 使用了OpenvSwitch软件,系统的libpcap和netmap。
- bsd-bridge: in-kernel FreeBSD bridging,使用了基于mbuf的设备驱动。
- 实验结论
- 无数据备份的netmap数据转运可以轻松地达到line rate。
- libpcap emulation库会增加很大的overhead,具体原因未查清。
- 在OpenvSwitch和Click上使用netmap的libpcap emulation替代系统的libpcap会有4~8倍的速度提升,意味着netmap API应用到实际的应用中很有效果。
- 实验说明:
-
整体实验总结
- netmap比应用中的标准API快4~40倍不等。
- 数据备份代价很昂贵,但即使加上数据备份,netmap也会带来很大的速度提升。
- 基于skbuf/mbuf的API需要250 ns/pkt,而基于netmap的packet generator只需20-30 ns/pkt。
-
Application porting
netmap的libpcap emulation库替换标准libpcap时非常方便,但是应用程序中的其他部分可能会影响netmap I/O 子系统的速度。比如 OpenvSwitch和Click:- OpenvSwitch: 其原始代码中存在一个expensive event loop,使得速度最大为70 Kpps,即使改为netmap模式也几乎没有提升。因此需要重构这个event loop并将系统分到两个进程,便可达到780 Kpps,更换为netmap的libpcap后可达到3 Mpps。
- Click: culprit时C++的allocator,它非常expensive,将其替换后可从0.40 Mpps提速到0.495 Mpps,若改为netmap模式,则可从1.3 Mpps提速到 3.95 Mpps。
总结与未来展望
-
定义:a framework that gives
userspace applications a very fast channel to exchange raw packets with the network adapter。 -
优点:
- netmap is not dependent on special hardware features
- its design makes very reasonable assumptions on the capabilities of the NICs
- netmap can give huge performance improvements to a wide range of applications using low/level packet I/O
-
已实现成果:
- FreeBSD and Linux versions
- the limited OS dependencies
- a libpcap emulation library
-
未来工作
- how the features of the netmap architecture can be exploited by the host transport/network stack
- how can they help in building efficient network support in virtualized platforms
所翻译文献
netmap:
a novel framework for fast packet I/O
Netmap Presentation Video