1 ---------------------------------
3 --- @brief Defines general utility functions.
5 --- @todo local unpackers ... crashes lua2dox parser
6 ---------------------------------
8 local
bor,
band,
bnot, rshift, lshift, bswap = bit.bor, bit.band, bit.bnot, bit.rshift, bit.lshift, bit.bswap
10 local format =
string.format
11 local random, log, floor = math.random, math.log, math.floor
13 --- Print a formatted
string.
19 return print(str:format(...))
22 --- Print a formatted error
string.
27 error(str:format(...), 2)
37 for i, v in ipairs(l) do
49 for i, v in ipairs(t) do
77 for i, v in ipairs(vals) do
79 v = v:gsub("\"", "\"\"")
81 -- fields just containing \
n or \r but not \
n\r are not required to be quoted by RFC 4180...
82 -- but I doubt that most parser could handle this ;)
83 if v:find("\
n") or v:find("\r") or v:find("\"") or v:find(",") then
84 vals[i] = ("\"%s\""):format(v)
87 return table.concat(vals, ",")
95 return print(
toCsv(...))
98 --- Get the time to wait (in byte-times) for the next packet based on a poisson process.
99 --- @param average the average wait time between two packets
100 --- @returns the number of byte-times to wait to achieve the given average wait-time
102 return floor(-log(1 - random()) / (1 / average) + 0.5)
112 return 10^10 / 8 / (rate * 10^6) - size - 24
115 --- Byte swap for 16 bit integers
116 --- @param
n 16 bit integer
117 --- @return Byte swapped integer
119 return
bor(rshift(
n, 8), lshift(
band(n, 0xFF), 8))
125 _G.bswap = bswap -- export bit.bswap to global namespace to be consistent with
bswap16
136 int gettimeofday(
struct timeval* tv,
void* tz);
140 local tv =
ffi.new(
"struct timeval")
143 ffi.C.gettimeofday(tv, nil)
144 return tonumber(tv.tv_sec) + tonumber(tv.tv_usec) / 10^6
150 --- @param data cdata to calculate the
checksum for.
151 --- @param len Number of bytes to calculate the
checksum for.
152 --- @return 16 bit integer
154 data =
ffi.cast("uint16_t*", data)
156 for i = 0, len / 2 - 1 do
159 cs =
band(cs, 0xFFFF) + 1
165 --- Parse a
string to a MAC address
166 --- @param mac address in
string format
167 --- @return address in mac_address format or nil if invalid address
169 local bytes = {
string.match(mac,
'(%x+)[-:](%x+)[-:](%x+)[-:](%x+)[-:](%x+)[-:](%x+)')}
174 if bytes[i] == nil then
177 bytes[i] = tonumber(bytes[i], 16)
178 if bytes[i] < 0 or bytes[i] > 0xFF then
183 addr =
ffi.
new("struct mac_address")
185 addr.uint8[i] = bytes[i + 1]
190 --- Parse a
string to an IP address
191 --- @return address
ip address in ip4_address or ip6_address format or nil if invalid address
192 --- @return
boolean true if IPv4 address, false otherwise
196 if address == nil then
202 --- Parse a
string to an IPv4 address
203 --- @param ip address in
string format
204 --- @return address in uint32 format or nil if invalid address
207 local bytes = {
string.match(ip,
'(%d+)%.(%d+)%.(%d+)%.(%d+)')}
212 if bytes[i] == nil then
215 bytes[i] = tonumber(bytes[i])
216 if bytes[i] < 0 or bytes[i] > 255 then
224 ip =
bor(lshift(ip, 8), bytes[i])
230 int inet_pton(
int af,
const char *src,
void *dst);
233 --- Parse a
string to an IPv6 address
234 --- @param ip address in
string format
235 --- @
return address in ip6_address format or nil
if invalid address
238 local LINUX_AF_INET6 = 10 --preprocessor constant of Linux
239 local tmp_addr =
ffi.
new("union ip6_address")
240 local res =
ffi.C.inet_pton(LINUX_AF_INET6, ip, tmp_addr)
245 local addr =
ffi.
new("union ip6_address")
246 addr.uint32[0] = bswap(tmp_addr.uint32[3])
247 addr.uint32[1] = bswap(tmp_addr.uint32[2])
248 addr.uint32[2] = bswap(tmp_addr.uint32[1])
249 addr.uint32[3] = bswap(tmp_addr.uint32[0])
254 --- Retrieve the system time with microseconds accuracy.
255 --- @todo use some C function to get microseconds.
256 --- @return System time in hh:mm:ss.uuuuuu format.
260 s = math.floor(t) -- round to seconds
261 u = t - s -- micro seconds
262 m = math.floor(s / 60) -- total minutes
263 s = s - m * 60 -- remaining seconds
264 h = math.floor(m / 60) -- total hours
265 m = m - h * 60 -- remaining minutes
266 h = h % 24 -- hour of the day
267 s = s + u -- seconds + micro seconds
268 return format("%02d:%02d:%02.6f", h, m, s)
271 --- Print a hex
dump of cdata.
272 --- @param data The cdata to be dumped.
273 --- @param bytes Number of bytes to
dump.
275 local data =
ffi.cast("uint8_t*", data)
276 for i = 0, bytes - 1 do
277 if i % 16 == 0 then --
new line
278 write(format(" 0x%04x: ", i))
281 write(format("%02x", data[i]))
283 if i % 2 == 1 then -- group 2 bytes
286 if i % 16 == 15 then -- end of 16 byte line
294 --- @param args Arbitrary amount of tables to get merged.
297 if select(
"#", ...) > 0 then
298 table = select(1, ...)
299 for i = 2, select("
#", ...) do
300 for k,v in pairs(select(i, ...)) do
308 --- Return all integerss in the
range [start, max].
309 --- @param max upper bound
310 --- @param start lower bound, default = 1
311 function
range(max, start, ...)
316 return start,
range(max, start + 1, select(2, ...))
320 local sar = bit.arshift
322 --- Increment a wrapping counter, i.e. (val + 1) % max
323 --- This function is optimized to generate branchless code and faster than a naive modulo-based implementation.
324 --- @note: all attempts to wrap this in a nice and simple class have failed (~30% performance impact).
325 --- @param val Current value (number)
326 --- @param max Maximum allowed value of val (number)
327 --- @return Incremented and wrapped number
329 return
band(val + 1, sar(val - max + 1, 31))
332 local unpackers = setmetatable({}, { __index =
function(
self,
n)
333 local func = loadstring(([[
335 return ]] .. (
"tbl[%d], "):rep(
n):sub(0, -3) .. [[
338 rawset(
self,
n, func)
342 --- unpack() with support for arrays with 'holes'.
343 --- @param tbl Table to unpack
344 --- @return Unpacked values
345 function unpackAll(tbl)
346 return unpackers[table.maxn(tbl)](tbl)
function rateToByteDelay(rate, size)
TODO.
local ffi
low-level dpdk wrapper
function checksum(data, len)
Calculate a 16 bit checksum.
function getTimeMicros()
Retrieve the system time with microseconds accuracy.
function parseIPAddress(ip)
Parse a string to an IP address.
function mg_filter_5tuple build(numCategories)
Builds the filter with the currently added rules.
function bswap16(n)
Byte swap for 16 bit integers.
function mod band(mask1, mask2, result)
Bitwise and.
function range(max, start,...)
Return all integerss in the range [start, max].
function pkt dump(bytes)
Dumps the packet data cast to the best fitting packet struct.
function tostringall(...)
TODO.
function mod bor(mask1, mask2, result)
Bitwise or.
function mergeTables(...)
Merge tables.
function tonumberall(...)
TODO.
function printf(str,...)
Print a formatted string.
function printCsv(...)
TODO.
function dumpHex(data, bytes)
Print a hex dump of cdata.
function parseIP6Address(ip)
Parse a string to an IPv6 address.
local ip
IP4 protocol constants.
function incAndWrap(val, max)
Increment a wrapping counter, i.e.
function mod bnot(mask, result)
Bitwise not.
n
Create a new array of memory buffers (initialized to nil).
function errorf(str,...)
Print a formatted error string.
function poissonDelay(average)
Get the time to wait (in byte-times) for the next packet based on a poisson process.
function parseMacAddress(mac)
Parse a string to a MAC address.
function mapVarArg(f,...)
TODO.
function parseIP4Address(ip)
Parse a string to an IPv4 address.