在艺术家看来,使用MoonGen + DPDK + Lua产生流量在实际条件下中和DDoS攻击需要进行初步测试和各种技术的测试。 网络设备和软件应在接近真实条件的人工条件下进行测试-密集的流量模拟攻击。 没有这样的实验,就很难获得有关任何复杂工具的特定功能和局限性的可靠信息。
在本文中,我们将介绍Qrator Labs中使用的一些流量生成方法。
警告我们强烈建议读者不要尝试使用上述工具来攻击实际基础结构的对象。 进行DoS攻击的组织应受到法律惩罚,并可能导致严厉的处罚。 Qrator Labs在隔离的实验室环境中进行所有测试。
现代技术水平
我们区域的一项重要任务是使10G以太网接口充满小数据包,这意味着要处理14.88 Mpps(每秒数百万个数据包)。 在下文中,我们考虑最小的以太网网络数据包-64字节-因为我们的主要兴趣是使每单位时间传输的数据包数量最大化。 一个简单的计算表明,我们只有大约67纳秒的时间来处理一个这样的数据包。
只是为了进行比较,这个时间接近现代处理器如果错过缓存就需要从内存中获取一条数据的时间。 当我们开始使用40G和100G以太网接口并尝试将其完全饱和到线速(网络设备可能达到的最大性能)时,一切都会变得更加复杂。
由于在通常情况下,数据流通过用户空间(用户空间)中的应用程序,然后通过内核,最后进入网络控制器(NIC),因此第一个也是最直接的想法是尝试直接在内核中配置数据包生成。
这种解决方案的一个例子是核模块
pktgen [2]。 这种方法允许您显着提高性能,但不够灵活,因为内核中源代码的微小变化会导致较长的构建周期,内核模块乃至整个系统的重新启动,实际上是测试,这降低了整体生产率(也就是说,需要程序员花费更多时间和努力)。
另一种可能的方法是获得从用户空间到网络控制器内存缓冲区的直接访问。 这条路径比较复杂,但是值得努力以实现更高的生产率。 缺点包括高复杂度和低灵活性。 这种方法的示例是
netmap ,
PF_RING和
DPDK [4]。
实现高性能的另一种有效方法(尽管成本很高)是不使用通用设备,而是使用专用设备。 例如:
Ixia 。
还有一些基于DPDK的使用脚本的解决方案,这些解决方案增加了控制生成器参数的灵活性,还允许您更改启动期间生成的包的类型。 下面,我们将介绍使用其中一种工具MoonGen的经验。
MoonGen建筑
MoonGen的独特功能是:
- 在用户空间中处理DPDK数据是提高性能的主要原因。
- Lua [ 5 ]堆栈,在顶层具有简单的脚本,在底层具有对用C编写的DPDK库的绑定;
- 借助JIT(及时)技术,Lua脚本的运行速度足够快,这在一定程度上与公认的关于脚本语言有效性的观点相矛盾。
MoonGen可以看作是DPDK库周围的Lua包装器。 在Lua用户界面级别上至少可见以下DPDK操作:
- 配置网络控制器;
- 分配和直接访问池和内存缓冲区,出于优化目的,应将它们分配在连续对齐的区域中;
- 直接访问网络控制器的RSS队列;
- 考虑到内存访问的异构性(NUMA和CPU关联性),用于管理计算流的API [ 12 ]。

MoonGen体系结构,来自材料的方案[
1 ]。
文根
MoonGen是基于DPDK库的脚本化高速数据包生成器。 Lua脚本控制着整个过程:用户创建的脚本负责创建,修改和发送软件包。 多亏了非常快的LuaJIT和DPDK数据包处理库,该体系结构允许您仅使用一个CPU内核就可以使10 Gb以太网接口与64字节数据包达到饱和。 即使Lua脚本修改了每个软件包,MoonGen仍可让您达到此速度。 它不使用诸如重用网络控制器相同缓冲区之类的技巧。
MoonGen还可以接收数据包,即检查被测系统丢弃了哪些数据包。 由于数据包接收仅由自定义Lua脚本控制,因此它也可以用于创建更复杂的测试脚本。 例如,您可以使用MoonGen的两个实例相互建立连接。 这种配置尤其可以用于测试所谓的中间盒(发送和接收流量的点之间的设备),例如防火墙。 MoonGen专注于四个主要领域:
- 高性能和多核扩展:在单个CPU核上每秒超过2000万个数据包;
- 灵活性:每个软件包都是根据用户创建的Lua脚本实时生成的;
- 精确的时间戳:在普通(商品)硬件上,时间戳的精确度为毫秒;
- 精确控制发送数据包之间的间隔:在普通硬件上可靠生成所需的模式和流量类型。
DPDK
DPDK代表数据平面开发套件,它由一些库组成,这些库的主要功能是提高在各种中央处理器体系结构上生成网络数据包的性能。
在当今计算机网络已成为人类通信基础的世界中,性能,带宽和延迟已成为无线网络和电缆基础设施等系统的越来越关键的参数,包括其所有单独组件:路由器,负载平衡器,防火墙; 以及应用领域:媒体传输(流),VoIP等。
DPDK是一种构建测试和脚本的轻巧方便的方法。 用户空间内的数据传输是我们很少观察到的,这主要是因为大多数应用程序通过操作系统和内核堆栈与网络设备进行通信,这与DPDK模型相反。
a
Lua的存在的主要目的是提供简单灵活的表达工具,这些工具可扩展用于特定的当前任务,而不是仅适用于一个编程范例的一组原语。 结果,基本语言非常轻巧-整个解释器仅占用
180 kB的编译形式,并且可以轻松地适应各种可能的实现。
Lua是一种动态语言。 它非常紧凑,几乎可以放在任何设备上。 Lua支持一小部分类型:布尔值,数字(双精度浮点数)和字符串。 常规数据结构(例如数组,集合和列表)可以由Lua中唯一的内置数据结构表示-表是异构异构数组。
Lua使用JIT(及时)编译,因此作为一种脚本语言,它的性能可与C [
10 ]之类的编译语言相媲美。
为什么选择月亮根
作为一家专门消除DDoS攻击的公司,Qrator Labs需要一种可靠的方法来创建,升级和测试自己的安全解决方案。 对于后者-测试,需要各种模拟实际攻击的流量生成方法。 但是,要在OSI模型的2-3个级别上模拟危险而又简单的洪灾攻击并非易事,主要是因为难以在数据包生成中实现高性能。
换句话说,对于一家致力于DDoS持续可用性和中和的公司而言,在隔离的实验室环境中模拟各种DoS攻击是一种了解作为公司硬件系统一部分的各种设备在实际情况下的行为的一种方式。
MoonGen是在最少的CPU内核下生成接近于网络控制器限制的流量值的好方法。 与用于产生高流量值的许多其他选项相比,用户空间内的数据传输显着提高了所讨论堆栈的性能(MoonGen + DPDK)。 使用纯DPDK需要付出更多的努力,因此您对我们优化性能的渴望不会感到惊讶。 我们还支持原始MoonGen存储库的克隆[
7 ],以扩展我们自己的测试的功能和实现。
为了获得最大的灵活性,用户使用Lua脚本设置生成软件包的逻辑,这是MoonGen的主要功能之一。 在相对简单的数据包处理的情况下,此解决方案的运行速度足够快,足以使单个CPU内核上的10G接口饱和。 修改传入软件包和创建新软件包的一种典型方法是使用相同类型的软件包,其中仅某些字段会发生变化。
一个示例是l3-tcp-syn-ack-flood测试,如下所述。 请注意,可以在同一缓冲区中对程序包进行任何修改,事实证明在上一步中生成或接收到该程序包。 确实,这样的分组转换非常快速地执行,因为它们不涉及昂贵的操作,例如系统调用,对存储器的潜在非缓存部分的访问等。
在Qrator Labs硬件上进行测试
Qrator Labs在实验室中对各种设备进行所有测试。 在这种情况下,我们使用了以下网络接口控制器:
- 英特尔82599ES 10G
- Mellanox ConnectX-4 40G
- Mellanox ConnectX-5 100G
我们单独指出,当使用在10G以上标准上运行的网络控制器时,性能问题变得更加严重。 如今,不可能用一个内核使40G接口饱和,尽管使用少量内核已经是现实的。
在Mellanox制造的网络控制器的情况下,可以使用制造商提供的调整指南[
3 ]来更改设备的某些参数和设置。 这样可以提高性能,在某些特殊情况下,还可以加深NIC的行为。 其他制造商可能会为自己的专业用途的高性能设备提供类似的文档。 即使您无法在公共领域中找到此类文档,也应直接与制造商联系。 在我们的案例中,Mellanox的代表非常友善,除了提供文档外,还迅速回答了我们的问题,因此我们设法实现了带钢100%的利用率,这对我们来说非常重要。
TCP SYN泛洪测试
L3-tcp-syn-ack-flood是模拟像SYN Flood [
6 ]这样的攻击的示例。 这是来自MoonGen主存储库的l3-tcp-syn-flood测试的扩展Qrator Labs版本,存储在我们的存储库克隆中。
我们的测试可以运行三种过程:
- 从头开始生成TCP SYN数据包流,更改必填字段,例如源IP地址,源端口号等。
- 根据TCP为每个接收到的SYN包创建一个有效的ACK响应;
- 根据TCP协议,为每个收到的ACK数据包创建一个有效的SYN-ACK响应。
例如,用于创建ACK响应的内部(分别是“最热”)代码循环如下:
local tx = 0 local rx = rxQ:recv(rxBufs) for i = 1, rx do local buf = rxBufs[i] local pkt = buf:getTcpPacket(ipv4) if pkt.ip4:getProtocol() == ip4.PROTO_TCP and pkt.tcp:getSyn() and (pkt.tcp:getAck() or synack) then local seq = pkt.tcp:getSeqNumber() local ack = pkt.tcp:getAckNumber() pkt.tcp:unsetSyn() pkt.tcp:setAckNumber(seq+1) pkt.tcp:setSeqNumber(ack) local tmp = pkt.ip4.src:get() pkt.ip4.src:set(pkt.ip4.dst:get()) pkt.ip4.dst:set(tmp) …
创建响应包的总体思路如下。 首先,您需要从RX队列中删除数据包,然后检查数据包类型是否与预期的类型匹配。 如果是巧合,请通过修改原始软件包的某些字段来准备答案。 最后,使用相同的缓冲区将创建的数据包放入TX队列。 为了提高性能,我们不对数据包进行一个接一个的修改,而是对其进行汇总,从RX队列中提取所有可用的数据包,创建相应的响应,然后将它们全部放入TX队列中。 尽管在一个软件包上进行了大量的操作,但性能仍然很高,这主要是由于Lua JIT将所有这些操作编译为少量的处理器指令这一事实。 许多其他测试,不仅是TCP SYN / ACK,都基于相同的原理进行。
下表显示了使用Mellanox ConnectX-4进行SYN泛洪测试(无响应尝试的SYN生成)的结果。 此NIC有两个40G端口,一个端口的理论性能上限为59.52 Mpps,两个端口为2 * 50 Mpps。 将NIC连接到PCIe的特定实现在某种程度上限制了带宽(给定2 * 50而不是预期的2 * 59.52)。
每个端口的核心 | 1个端口,Mpps | 2个端口,每个端口Mpps |
1个 | 20 | 19 |
2 | 38 | 36 |
3 | 56.5 | 47 |
4 | 59.5 | 50 |
SYN洪水测试; NIC:Mellanox Technologies MT27700系列(ConnectX-4),双40G端口; CPU:英特尔®至强®银牌4114 CPU @ 2.20GHz下表显示了在具有一个100G端口的Mellanox ConnectX-5上进行的相同SYN泛洪测试的结果。
核心 | 点数 |
1个 | 35 |
2 | 69 |
3 | 104 |
4 | 127 |
5 | 120 |
6 | 131 |
7 | 132 |
8 | 144 |
SYN洪水测试; NIC:Mellanox Technologies MT27800系列(ConnectX-5),单个100G端口; CPU:英特尔®至强®银牌4114 CPU @ 2.20GHz请注意,在所有情况下,我们在少数处理器内核上都达到了理论性能上限的96%以上。
捕获传入流量并将其保存到PCAP文件
该测试的另一个示例是rx-to-pcap,它尝试捕获所有传入流量并将其保存到一定数量的PCAP文件中[
8 ]。 尽管此测试并不特别关注软件包的生成,但它证明了通过用户空间组织数据传输中最薄弱的环节是文件系统。 甚至tmpfs虚拟文件系统也会显着降低传输速度。 在这种情况下,需要使用中央处理器的8个内核才能使用14.88 Mpps,而只有一个内核足以接收(以及重置或重定向)相同数量的流量。
下表显示了已接收并保存到位于SSD(第二列)或tmpfs文件系统(第三列)上ext2文件系统中的PCAP文件中的流量(以Mpps为单位)。
核心 | 在SSD,Mpps上 | 在tmpfs,Mpps上 |
1个 | 1.48 | 1.62 |
2 | 4 | 4.6 |
3 | 6.94 | 8.1 |
4 | 9.75 | 11.65 |
5 | 12.1 | 13.8 |
6 | 13.38 | 14.47 |
7 | 14.4 | 14.86 |
8 | 14.88 | 14.88 |
Rx-to-pcap测试; NIC:Intel 82599ES 10千兆位; CPU:Intel®Xeon®CPU E5-2683 v4 @ 2.10GHzMoonGen修改:tman任务管理器
我们还想向读者介绍我们自己的MoonGen功能扩展,它提供了另一种启动一组测试任务的方式。 这里的主要思想是将特定于每个任务的常规配置和设置分开,从而允许您同时运行任意数量的不同任务(即Lua脚本)。 在我们的MoonGen存储库的克隆中,介绍了使用任务管理器[
9 ]实现MoonGen的实现,这里我们仅简要列出其主要功能。
新的命令行界面使您可以同时运行多个不同类型的任务。 基本方案如下:
./build/tman [tman options...] [-- <task1-file> [task1 options...]] [-- <task2-file> [task2 options...]] [-- ...]
此外,./build/tman -h提供了详细的帮助。
但是,有一个限制-常规Lua作业文件与
tman界面不兼容。
tman作业
文件应明确定义以下对象:
- 描述作业参数的配置(解析器)功能;
- 任务功能(taskNum,txInfo,rxInfo,args),描述了实际的任务过程。 这里的txInfo和rxInfo分别是RX和TX队列的数组; args包含任务管理器的参数和任务本身。
- 示例可以在examples / tman中找到。
使用任务管理器为您提供了运行异构测试的更多灵活性。
结论
事实证明,MoonGen提供的方法非常适合我们的目标,并且使员工满意所获得的结果。 我们获得了高性能的工具,同时保持测试环境和语言非常简单。 该设置的高性能要归功于两个主要功能:直接访问网络接口控制器缓冲区和Lua中的即时编译技术。
通常,为网络接口控制器的性能达到理论上的上限是可行的任务。 正如我们已经显示的,单个内核可能足以使10G端口饱和,而100G端口的满载对于大量内核而言并不会带来特殊的问题。
我们特别感谢Mellanox团队提供的设备帮助以及MoonGen团队对纠正错误的反应。
用料
- MoonGen:可编写脚本的高速数据包生成器-Paul Emmerich等人,2015年Internet测量会议(IMC'15),2015年
- pktgen
- Mellanox调整指南
- 数据平面开发套件
- a
- 同步洪水
- Qrator Labs的MoonGen存储库克隆
- PCAP文件格式
- 任务经理
- Lua表演
- 网络功能虚拟化白皮书
- NUMA,非均匀内存访问