1 ---------------------------------
5 ---------------------------------
7 --- high-level dpdk wrapper
9 local
ffi = require
"ffi"
10 local dpdkc = require
"dpdkc"
11 local serpent = require
"Serpent"
13 -- DPDK constants (lib/librte_mbuf/rte_mbuf.h)
14 -- TODO:
import more constants here
15 mod.PKT_RX_VLAN_PKT = 0x0001
16 mod.PKT_RX_IEEE1588_TMST = 0x0400
17 mod.PKT_RX_IPSEC_SECP = 0x0800
18 mod.PKT_RX_SECERR_LSB = 0x1000
19 mod.PKT_RX_SECERR_MSB = 0x2000
21 mod.PKT_TX_IPV4_CSUM = 0x1000
22 mod.PKT_TX_TCP_CKSUM = 0x2000
23 mod.PKT_TX_UDP_CKSUM = 0x6000
24 mod.PKT_TX_NO_CRC_CSUM = 0x0001
25 mod.PKT_TX_IPSEC = 0x0002
26 mod.PKT_TX_VLAN_PKT = 0x0800
27 mod.PKT_TX_IEEE1588_TMST = 0x8000
29 local
function fileExists(f)
30 local file = io.open(f, "r")
39 --- Inits DPDK. Called by MoonGen on startup.
42 dpdkc.register_pmd_drivers()
43 -- TODO: support arbitrary dpdk configurations by allowing configuration in the form ["cmdLine"] = "foo"
44 local cfgFileLocations = {
46 "./lua/dpdk-conf.lua",
47 "../lua/dpdk-conf.lua",
48 "/etc/moongen/dpdk-conf.lua"
51 for _, f in ipairs(cfgFileLocations) do
53 cfgScript = loadfile(f)
54 setfenv(cfgScript, setmetatable({ DPDKConfig =
function(arg) cfg = arg end }, { __index = _G }))
55 local ok, err = pcall(cfgScript)
57 print("could not load DPDK
config: " .. err)
61 print("
config file does not contain DPDKConfig statement")
69 print("no DPDK
config found, using defaults")
74 --
default: use all the cores
75 local cpus = io.open(
"/proc/cpuinfo",
"r")
77 for cpu in cpus:read(
"*a"):gmatch(
"processor : (%d+)") do
78 cfg.cores[#cfg.cores + 1] = tonumber(cpu)
82 if type(cfg.cores) ==
"number" then
85 -- TODO: support more than 32 cores but bit operations on 64 bit types are currently not supported in luajit
87 if bit.band(coreMask, bit.lshift(1, i)) ~= 0 then
91 if cfg.cores >= 2^32 then
92 print(
"Warning: more than 32 cores are currently not supported in bitmask format, sorry")
93 print(
"Use a table as a work-around")
96 elseif type(cfg.cores) == "table" then
99 for i, v in ipairs(cores) do
100 coreMask = coreMask + 2^v
103 local argv = {
"MoonGen" }
104 if cfg.noHugeTlbFs then
105 argv[#argv + 1] =
"--no-huge"
107 argv[#argv + 1] = (
"-c0x%X"):format(coreMask)
108 argv[#argv + 1] =
"-n" .. (cfg.memoryChannels or 4) -- todo:
auto-detect
110 dpdkc.rte_eal_init(argc,
ffi.new(
"const char*[?]", argc, argv))
115 void launch_lua_core(
int core, uint64_t task_id,
char* userscript,
char* args);
117 void free(
void* ptr);
118 uint64_t generate_task_id();
119 void store_result(uint64_t task_id,
char* result);
120 char* get_result(uint64_t task_id);
123 local
function checkCore()
124 if MOONGEN_TASK_NAME ~= "master" then
125 error("[ERROR] This function is only available on the master task.", 2)
134 function task:
new(core)
136 local obj = setmetatable({
137 --
double instead of uint64_t is easier here and okay (unless you want to start more than 2^53 tasks)
138 id = tonumber(
ffi.C.generate_task_id()),
145 --- Wait for a task and return any arguments returned by the task
149 if dpdkc.rte_eal_get_lcore_state(self.core) ~= dpdkc.RUNNING then
151 local result = dpdkc.get_result(self.
id)
152 if result == nil then
156 local resultString =
ffi.
string(result)
158 return unpackAll(loadstring(resultString)())
164 function task:isRunning()
166 if not tasks[self.core] or task[self.core].
id ~= self.
id then
167 -- something else or nothing is
running on this core
170 -- this task is still on this cora, but is it still
running?
171 return dpdkc.rte_eal_get_lcore_state(core) == dpdkc.RUNNING
175 --- Launch a LuaJIT VM on a core with the given arguments.
176 --- TODO: use proper serialization and only pass strings
179 local args = serpent.
dump({ ... })
180 local task = task:
new(core)
181 local buf =
ffi.
new("
char[?]",
#args + 1)
183 local userscript =
ffi.new(
"char[?]", #
mod.userScript + 1)
184 ffi.copy(userscript,
mod.userScript)
185 dpdkc.launch_lua_core(core, task.id, userscript, buf)
189 --- launches the lua file on the first
free core
190 function mod.launchLua(...)
192 for i = 2,
#cores do -- skip master
193 local core = cores[i]
194 local status = dpdkc.rte_eal_get_lcore_state(core)
195 if status == dpdkc.FINISHED then
196 dpdkc.rte_eal_wait_lcore(core)
197 -- should be guaranteed to be in WAIT state now according to DPDK documentation
198 status = dpdkc.rte_eal_get_lcore_state(core)
200 if status == dpdkc.WAIT then -- core is in WAIT state
201 return mod.launchLuaOnCore(core, ...)
204 error(
"not enough cores to start this lua task")
208 int usleep(
unsigned int usecs);
211 --- waits until all slave cores have finished their jobs
214 local allCoresFinished = true
215 for i = 2,
#cores do -- skip master
216 local core = cores[i]
217 if dpdkc.rte_eal_get_lcore_state(core) == dpdkc.RUNNING then
218 allCoresFinished =
false
222 if allCoresFinished then
229 function mod.getCores()
233 ---
get the CPU
's TSC
234 function mod.getCycles()
235 return dpdkc.rte_rdtsc()
238 --- get the TSC frequency
239 function mod.getCyclesFrequency()
240 return tonumber(dpdkc.rte_get_tsc_hz())
243 --- gets the time in seconds
244 function mod.getTime()
245 return tonumber(mod.getCycles()) / tonumber(mod.getCyclesFrequency())
248 --- set total run time of the test (to be called from master core on startup, shared between all cores)
249 function mod.setRuntime(time)
250 dpdkc.set_runtime(time * 1000)
253 --- Returns false once the app receives SIGTERM or SIGINT, the time set via setRuntime expires, or when a thread calls dpdk.stop().
254 -- @param extraTime additional time in milliseconds before false will be returned
255 function mod.running(extraTime)
256 return dpdkc.is_running(extraTime or 0) == 1 -- luajit-2.0.3 does not like bool return types (TRACE NYI: unsupported C function type)
259 --- request all tasks to exit
264 --- Delay by t milliseconds. Note that this does not sleep the actual thread;
265 --- the time is spent in a busy wait loop by DPDK.
266 function mod.sleepMillis(t)
267 dpdkc.rte_delay_ms_export(t)
270 --- Delay by t microseconds. Note that this does not sleep the actual thread;
271 --- the time is spent in a busy wait loop by DPDK. This means that this sleep
272 --- is somewhat more accurate than relying on the OS.
273 function mod.sleepMicros(t)
274 dpdkc.rte_delay_us_export(t)
277 --- Sleep by t milliseconds by calling usleep().
278 function mod.sleepMillisIdle(t)
279 ffi.C.usleep(t * 1000)
282 --- Sleep by t microseconds by calling usleep().
283 function mod.sleepMicrosIdle(t)
287 --- Get the core and socket id for the current thread
288 function mod.getCore()
289 return dpdkc.get_current_core(), dpdkc.get_current_socket()
292 function mod.disableBadSocketWarning()
293 MOONGEN_IGNORE_BAD_NUMA_MAPPING = true
function mod waitForSlaves()
waits until all slave cores have finished their jobs
local ffi
low-level dpdk wrapper
function mod free(buf)
Free off-heap allocated object.
function pkt dump(bytes)
Dumps the packet data cast to the best fitting packet struct.
function task wait()
Wait for a task and return any arguments returned by the task.
local mod
high-level dpdk wrapper
function mod config(...)
Configure a device.
function mod init()
Inits DPDK. Called by MoonGen on startup.
function mod launchLuaOnCore(core,...)
Launch a LuaJIT VM on a core with the given arguments.
function mod running(extraTime)
Returns false once the app receives SIGTERM or SIGINT, the time set via setRuntime expires...