1 ---------------------------------
5 ---------------------------------
7 -- vim:ts=4:sw=4:noexpandtab
10 local
ffi = require
"ffi"
11 local dpdkc = require
"dpdkc"
12 local dpdk = require
"dpdk"
13 local ns = require
"namespaces"
14 local serpent = require
"Serpent"
17 void* malloc(
size_t size);
19 void* alloc_huge(
size_t size);
25 --- Off-heap allocation, not garbage-collected.
26 --- @param ctype a
ffi type, must be a pointer or array type
27 --- @param size the amount of memory to allocate
28 function mod.alloc(ctype, size)
29 return cast(ctype, C.malloc(size))
32 --- Free off-heap allocated
object.
33 function mod.free(buf)
37 --- Off-heap allocation on huge pages, not garbage-collected.
39 --- TODO:
add a
free function for this
40 function mod.allocHuge(ctype, size)
41 return cast(ctype, C.alloc_huge(size))
45 local mempoolCache = ns:
get()
47 local cacheEnabled =
false
49 --- Enable mempool recycling.
50 --- Calling
this function enables the mempool cache. This prevents memory leaks
51 --- as DPDK cannot
delete mempools.
52 --- Mempools with the same parameters created on the same core will be recycled.
53 --- This is not yet enabled by
default because I
'm not 100% confident that it works
54 --- properly in all cases.
55 --- For example, mempools passed to other tasks will probably break stuff.
56 function mod.enableCache()
60 local function getPoolFromCache(socket, n, bufSize)
61 if not cacheEnabled then
65 mempoolCache.lock(function()
66 -- TODO: pass an iterator context to the callback
67 -- the context could then run functions like abort() or removeCurrent()
69 mempoolCache:forEach(function(key, pool)
73 if pool.socket == socket
75 and pool.bufSize == bufSize
76 and pool.core == dpdk.getCore() then
81 pool = mempoolCache[result].pool
82 mempoolCache[result] = nil
88 local buf = pool:alloc(bufSize)
89 ffi.fill(buf.data, buf.len, 0)
92 for _, v in ipairs(bufs) do
93 dpdkc.rte_pktmbuf_free_export(v)
99 --- Create a new memory pool.
100 --- Memory pools are recycled once the owning task terminates.
101 --- Call :retain() for mempools that are passed to other tasks.
102 --- A table with named arguments should be used.
103 --- @param args A table containing the following named arguments
104 --- @param n optional (default = 2047), size of the mempool
105 --- @param func optional, init func, called for each argument
106 --- @param socket optional (default = socket of the calling thread), NUMA association. This cannot be the only argument in the call.
107 --- @param bufSize optional the size of each buffer, can only be used if all other args are passed as well
108 function mod.createMemPool(...)
110 if type(args[1]) == "table" then
113 --print "[WARNING] You are using a depreciated method for calling createMemPool(...). createMemPool(...) should be used with named arguments."
114 if type(args[1]) == "function" then
116 args.socket = args[2]
118 elseif type(args[2]) == "number" then
120 args.socket = args[2]
123 -- DPDK recommends to use a value of n=2^k - 1 here
124 args.n = args.n or 2047
125 args.socket = args.socket or select(2, dpdk.getCore())
126 args.bufSize = args.bufSize or 2048
127 -- TODO: get cached mempool from the mempool pool if possible and use that instead
128 -- FIXME: the todo seems to be already implemented here.
129 local mem = getPoolFromCache(args.socket, args.n, args.bufSize) or dpdkc.init_mem(args.n, args.socket, args.bufSize)
133 -- TODO: make this dependent on bufSize
134 local buf = mem:alloc(1522)
136 bufs[#bufs + 1] = buf
138 for i, v in ipairs(bufs) do
139 dpdkc.rte_pktmbuf_free_export(v)
142 mempools[#mempools + 1] = {
144 socket = args.socket,
146 bufSize = args.bufSize,
147 core = dpdk.getCore()
152 --- Free all memory pools owned by this task.
153 --- All queues using these pools must be stopped before calling this.
154 function mod.freeMemPools()
155 if not cacheEnabled then
158 for _, mem in ipairs(mempools) do
159 mempoolCache[tostring(mem.pool)] = mem
165 mempool.__index = mempool
167 --- Retain a memory pool.
168 --- This will prevent the pool from being returned to a pool of pools once the task ends.
169 function mempool:retain()
170 for i, v in ipairs(mempools) do
171 if v.pool == self then
172 table.remove(mempools, i)
178 function mempool:alloc(l)
179 local r = dpdkc.alloc_mbuf(self)
187 --- Create a new array of memory buffers (initialized to nil).
188 function mempool:bufArray(n)
190 return setmetatable({
192 array = ffi.new("struct rte_mbuf*[?]", n),
198 local function alloc()
199 error("buf array not associated with a memory pool", 2)
202 --- Create a new array of memory buffers (initialized to nil).
203 -- This buf array is not associated with a memory pool.
204 function mod.createBufArray(n)
210 return setmetatable({
212 array = ffi.new("struct rte_mbuf*[?]", n),
217 mod.bufArray = mod.createBufArray
220 function bufArray:offloadUdpChecksums(ipv4, l2Len, l3Len)
221 ipv4 = ipv4 == nil or ipv4
222 l2_len = l2_len or 14
224 l3_len = l3_len or 20
225 for i = 0, self.size - 1 do
226 self.array[i].ol_flags = bit.bor(self.array[i].ol_flags, dpdk.PKT_TX_IPV4_CSUM, dpdk.PKT_TX_UDP_CKSUM)
227 self.array[i].pkt.header_lengths = l2_len * 512 + l3_len
229 dpdkc.calc_ipv4_pseudo_header_checksums(self.array, self.size, 20)
231 l3_len = l3_len or 40
232 for i = 0, self.size - 1 do
233 self.array[i].ol_flags = bit.bor(self.array[i].ol_flags, dpdk.PKT_TX_UDP_CKSUM)
234 self.array[i].pkt.header_lengths = l2_len * 512 + l3_len
236 dpdkc.calc_ipv6_pseudo_header_checksums(self.array, self.size, 30)
240 function bufArray:offloadIPSec(idx, mode, sec_type)
241 for i = 0, self.size - 1 do
242 local buf = self.array[i]
243 buf:offloadIPSec(idx, mode, sec_type)
247 --- If called, IP chksum offloading will be done for the first n packets
249 -- @param ipv4 optional (default = true) specifies, if the buffers contain ipv4 packets
250 -- @param l2Len optional (default = 14)
251 -- @param l3Len optional (default = 20)
252 -- @param n optional (default = bufArray.size) for how many packets in the array, the operation
254 function bufArray:offloadIPChecksums(ipv4, l2Len, l3Len, n)
255 -- please do not touch this function without carefully measuring the performance impact
256 -- FIXME: touched this.
258 ipv4 = ipv4 == nil or ipv4
261 l2_len = l2_len or 14
262 l3_len = l3_len or 20
264 local buf = self.array[i]
265 buf.ol_flags = bit.bor(buf.ol_flags, dpdk.PKT_TX_IPV4_CSUM)
266 buf.pkt.header_lengths = l2_len * 512 + l3_len
271 function bufArray:offloadTcpChecksums(ipv4, l2Len, l3Len)
272 ipv4 = ipv4 == nil or ipv4
273 l2_len = l2_len or 14
275 l3_len = l3_len or 20
276 for i = 0, self.size - 1 do
277 self.array[i].ol_flags = bit.bor(self.array[i].ol_flags, dpdk.PKT_TX_IPV4_CSUM, dpdk.PKT_TX_TCP_CKSUM)
278 self.array[i].pkt.header_lengths = l2_len * 512 + l3_len
280 dpdkc.calc_ipv4_pseudo_header_checksums(self.array, self.size, 25)
282 l3_len = l3_len or 40
283 for i = 0, self.size - 1 do
284 self.array[i].ol_flags = bit.bor(self.array[i].ol_flags, dpdk.PKT_TX_TCP_CKSUM)
285 self.array[i].pkt.header_lengths = l2_len * 512 + l3_len
287 dpdkc.calc_ipv6_pseudo_header_checksums(self.array, self.size, 35)
291 --- Offloads VLAN tags on all packets.
292 -- Equivalent to calling pkt:setVlan(vlan, pcp, cfi) on all packets.
293 function bufArray:setVlans(vlan, pcp, cfi)
294 local tci = vlan + bit.lshift(pcp or 0, 13) + bit.lshift(cfi or 0, 12)
295 for i = 0, self.size - 1 do
296 self.array[i].pkt.vlan_tci = tci
297 self.array[i].ol_flags = bit.bor(self.array[i].ol_flags, dpdk.PKT_TX_VLAN_PKT)
301 --- Allocates buffers from the memory pool and fills the array
302 function bufArray:alloc(size)
303 dpdkc.alloc_mbufs(self.mem, self.array, self.size, size)
306 --- Free all buffers in the array. Stops when it encounters the first one that is null.
307 function bufArray:freeAll()
308 for i = 0, self.size - 1 do
309 if self.array[i] == nil then
312 dpdkc.rte_pktmbuf_free_export(self.array[i])
317 --- Free the first n buffers.
318 function bufArray:free(n)
320 if self.array[i] ~= nil then
321 dpdkc.rte_pktmbuf_free_export(self.array[i])
326 function bufArray.__index(self, k)
327 -- TODO: is this as fast as I hope it to be?
328 return type(k) == "number" and self.array[k - 1] or bufArray[k]
331 function bufArray.__newindex(self, i, v)
332 self.array[i - 1] = v
335 function bufArray.__len(self)
340 local function it(self, i)
341 if i >= self.size then
344 return i + 1, self.array[i]
347 function bufArray.__ipairs(self)
353 ffi.metatype("struct mempool", mempool)
local ffi
low-level dpdk wrapper
function mod free(buf)
Free off-heap allocated object.
local mod
high-level dpdk wrapper
function ip4Addr add(val)
Add a number to an IPv4 address in-place.