学习了一下MoonGen,主要参考官网和tutorial。
usage introduction
Device setup
master
函数是必须的,用来进行设备的配置,一个简单的设置如下
1 | local device = require "device" |
如果要用到receive filter
configuration,要在创建的时候设置设备。在device.config
中,设置rssNQueues = N
,来创建N
个队列。此外,还可以通过rssFunctions
来控制hash值,选项有RSS_FUNCTION_IPV4
,.._IPV6
,.._IPVX_TCP
,.._IPVX_UDP
。示例如下:
1 | local device = require "device" |
packet generation
packets是异步发送、在memory buffer中生成的,所以需要一个在memory pool中的buffer array。
因为大多数packets应该是一样的,所以一般通过一个函数定义。
注意:应该在memory pool中定义packet的值,而不是在generation loop中,否则性能会大大下降。
最简单的方法就是在char buffer中手动设置一个ethernet header,示例如下:
1 | local dpdk = require "dpdk" |
简单一点,raw
buffer可以先被转换成各种包的格式,然后直接填就可以了。在lua/include/proto/
中可以找到定义的相应格式。比如:
1 | local mem = memory.createMemPool(function(buf) |
如果要定义一种新的格式,按照lua/include/proto/newProtocolTemplate.lua
的方式,拷贝并修改。
如果要修改某一种特定的包,在分配buffer后和enqueue之前修改,方法类似。
如果需要控制发包器的速度,通过调用函数queue:setRate(MBit/s)
如果需要暂停LuaJIT VM,通过dpdk.sleepMillis(time)
running parallel tasks
为了支持并行,通过引入dpdk.lauchLua("funcname", arg0, ...)
来用一个新的LuaJIT
VM跑一个新的slave task。一般的调用方法为
1 | local dpdk = require "dpdk" |
statistics
stats
模块提供了统计功能,收集完数据之后,可以被写到stdout
或者一些其他的文件中。支持的输出类型有plain
,csv
和ini
。
packet counter是和device绑定的,要创建一个新的packet
counter,可以使用rxCtr = stats:newDevRxCounter(device, "plain")
或者newDevTxCounter(..)
。
newPktRxCounter("your counter name", "plain")
或者newPktTxCounter(..)
可以通过调用它的countPacket(singleBuffer)
来将packet
buffer传递给它们来实现更新。
newManualTxCounter("your counter name", "plain")
可以手动计数。可以通过updateWithSize(packet_count, each_size)
来更新。
对于所有counter,update()
方法都可以频繁调用,可以显示当前数据。
histogram
模块可以收集频率方面的数据。
下面的示例使用了device和package两种计数器,packet size记在histogram里。
1 | local dpdk = require "dpdk" |
如果要使用manual
counter,可以通过queue:send()
的返回值来实时更新。注意到发送动作是异步的,但是返回值仍然可以用来做计数。和之前的一样,finalize()
函数可以用来输出最终结果。而updateWithSize()
输出每一秒的实时结果。示例如下:
1 | function send(queue) |
同时也可以在接收包的时候,可以对包的一些特定内容进行统计。示例如下:
1 | function recv(queue) |
timestamping
用来测时间戳的包定义在lua/include/proto/ptp.lua
。可以通过timestamping:newTimestamper(txq, rxq)
来创造一个新的timestamper。创建的timestamper可以在l2层使用,或者也可以通过udp传输。
以下的例子在两个queue之间每隔0.01s测量一次延迟。
1 | local ts = require "timestamping" |
task communication
moongen提供两种交流的方法。
一种是pipes。一般在一个公共背景下创建pipe,比如master函数。以下就是一个示例:
1 | local pipe = require "pipe" |
另一种是namespace,就是在LuaJIT VM之间声明用lua table表示的全局变量。
1 | local dpdk = require "dpdk" |
traffic patterns
有的时候网卡只支持固定速度,而却需要人为降速,这个时候moongen会通过在包之间添加gap(就是在空隙发送损坏的包)来达到降速的效果。
可以通过buf.setDelay(bytes)
来设置延时,如果要设置随机延时,有泊松分布的延时产生poissonDelay(average_wait)
。示例如下:
1 | function send(txDev) |