ntopng/scripts/lua/modules/plugins_consts_utils.lua
2020-01-30 11:27:15 +01:00

224 lines
7.2 KiB
Lua

--
-- (C) 2013-20 - ntop.org
--
local plugins_consts_utils = {}
local dirs = ntop.getDirs()
-- ##############################################
local AVAILABLE_CONSTS = {
flow = {
min_id = 1, max_id = 63, reuse_ids = true,
reserved_ids = {
status_normal = 0,
},
},
alert = {
min_id = 0, max_id = 255, reuse_ids = false,
}
}
-- ##############################################
local id_requests = {
flow = {},
alert = {}
}
-- ##############################################
local function assigned_ids_hname(const_type)
return string.format("ntopng.prefs.plugins_consts_utils.assigned_ids.const_type_%s", const_type)
end
-- ##############################################
local function assigned_id_key(const_type, const_key)
local hname = assigned_ids_hname(const_type)
return string.format("%s.const_key_%s", hname, const_key)
end
-- ##############################################
local function get_assigned_ids(const_type)
local hname = assigned_ids_hname(const_type)
local assigned_ids = ntop.getHashAllCache(hname) or {}
local cur_id_to_key = {}
local cur_key_to_id = {}
for const_id, const_key in pairs(assigned_ids) do
local const_id_n = tonumber(const_id)
if const_id_n < AVAILABLE_CONSTS[const_type]["min_id"] or const_id_n > AVAILABLE_CONSTS[const_type]["max_id"] then
traceError(TRACE_ERROR, TRACE_CONSOLE, string.format("Ignoring id %i outside boundaries for '%s'", const_id_n, const_type))
else
cur_id_to_key[const_id_n] = const_key
cur_key_to_id[const_key] = const_id_n
end
end
return cur_id_to_key, cur_key_to_id
end
-- ##############################################
local function commit_new_ids(const_type, new_ids)
local hname = assigned_ids_hname(const_type)
for const_key, const_id in pairs(new_ids) do
local const_id_s = string.format("%i", const_id)
-- Attempt to lookup for the id in the cache. Attempting to commit a new id to an existing
-- it, causes the old key to be reused the new key. This is used for example when reusing ids
local existing = ntop.getHashCache(hname, const_id)
if not isEmptyString(existing) then
traceError(TRACE_NORMAL, TRACE_CONSOLE, string.format("Reusing id %i '%s' to '%s'", const_id, existing, const_key))
ntop.delHashCache(hname, const_id_s)
local existing_kname = assigned_id_key(const_type, existing)
ntop.delCache(existing_kname)
end
-- Now it's time to set the new id, both in the hash table...
ntop.setHashCache(hname, const_id, const_key)
-- ... and as a single key
local kname = assigned_id_key(const_type, const_key)
ntop.setPref(kname, const_id_s)
end
end
-- ##############################################
function plugins_consts_utils.clear_id_requests(const_type)
id_requests[const_type] = {}
end
-- ##############################################
function plugins_consts_utils.request_id(const_type, const_key)
if not AVAILABLE_CONSTS[const_type] then
traceError(TRACE_ERROR, TRACE_CONSOLE, string.format("Unknown const type '%s'", const_type))
return
end
id_requests[const_type][#id_requests[const_type] + 1] = const_key
end
-- ##############################################
function plugins_consts_utils.assign_requested_ids(const_type)
if not AVAILABLE_CONSTS[const_type] then
traceError(TRACE_ERROR, TRACE_CONSOLE, string.format("Unknown const type '%s'", const_type))
return
end
local cur_id_to_key, cur_key_to_id = get_assigned_ids(const_type)
local available_ids = {}
local used_ids = {}
local new_ids = {}
local found_ids = {}
local deferred_requests = {}
local reused_ids = {}
-- Prepare used and available ids by iterating the current existing ids (i.e., those
-- that have already been assigned)
for i = AVAILABLE_CONSTS[const_type]["min_id"], AVAILABLE_CONSTS[const_type]["max_id"] do
if cur_id_to_key[i] then
used_ids[#used_ids + 1] = i
else
available_ids[#available_ids + 1] = i
end
end
for _, req in ipairs(id_requests[const_type]) do
if AVAILABLE_CONSTS[const_type]["reserved_ids"] and AVAILABLE_CONSTS[const_type]["reserved_ids"][req] then
-- Id among those reserved, so id is already assigned and there is nothing to do
elseif cur_key_to_id[req] then
-- Id found: already assigned, nothing to do
found_ids[#found_ids + 1] = cur_key_to_id[req]
elseif #available_ids > 0 then
-- At least an id is available in the pool of available ids
new_ids[req] = table.remove(available_ids, 1)
elseif AVAILABLE_CONSTS[const_type]["reuse_ids"] then
-- No ids available but reuse of old ids is enabled
deferred_requests[#deferred_requests + 1] = req
else
-- No ids available and reuse not allowed, unable to assign.
traceError(TRACE_ERROR, TRACE_CONSOLE, string.format("Unable to assign an id to '%s' for const type '%s'. No more ids available", req, const_type))
end
end
commit_new_ids(const_type, new_ids)
if #deferred_requests > 0 then
for _, used_id in ipairs(used_ids) do
local used_id_found = false
for _, found_id in ipairs(found_ids) do
if used_id == found_id then
-- Used id found during this run, cannot reuse it
used_id_found = true
break
end
end
if not used_id_found then
-- This id is used but not found so it means no plugin is using it (during this run) and it can be reused
reused_ids[table.remove(deferred_requests, 1)] = used_id
end
if #deferred_requests == 0 then
-- No more work to do
break
end
end
commit_new_ids(const_type, reused_ids)
if #deferred_requests > 0 then
for _, req in ipairs(deferred_requests) do
traceError(TRACE_ERROR, TRACE_CONSOLE, string.format("Unable to reuse any id for '%s' with const type '%s'.", req, const_type))
end
end
end
end
-- ##############################################
function plugins_consts_utils.get_assigned_id(const_type, const_key)
if not AVAILABLE_CONSTS[const_type] then
traceError(TRACE_ERROR, TRACE_CONSOLE, string.format("Unknown const type '%s'", const_type))
return
end
if AVAILABLE_CONSTS[const_type]["reserved_ids"] and AVAILABLE_CONSTS[const_type]["reserved_ids"][const_key] then
return AVAILABLE_CONSTS[const_type]["reserved_ids"][const_key]
end
-- Avoid reading the whole hash, just read the single key to re-use also ntopng internal caching mechanism
local kname = assigned_id_key(const_type, const_key)
local assigned_id = tonumber(ntop.getPref(kname))
if assigned_id == nil then
-- Not found in the internal cache, check the hash
local cur_id_to_key, cur_key_to_id = get_assigned_ids(const_type)
if cur_key_to_id[const_key] ~= nil then
return cur_key_to_id[const_key]
end
end
-- Make sure the index is within the configured bounds
if assigned_id then
if assigned_id < AVAILABLE_CONSTS[const_type]["min_id"] or assigned_id > AVAILABLE_CONSTS[const_type]["max_id"] then
traceError(TRACE_ERROR, TRACE_CONSOLE, string.format("Ignoring id %i outside boundaries for '%s'", assigned_id, const_type))
-- Clear it as it should have that value
assigned_id = nil
end
end
return assigned_id
end
return plugins_consts_utils