Implemented ASN user traffic breakdown (#9595)

This commit is contained in:
Manuel Ceroni 2025-09-02 12:19:04 +02:00 committed by GitHub
parent d006320a2e
commit 545306cbe2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 681 additions and 3 deletions

View file

@ -0,0 +1,94 @@
--
-- (C) 2013-25 - ntop.org
--
dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path
require "ntop_utils"
local flow_data = require "flow_data"
local format_utils = require "format_utils"
local flow_data_preset = require "flow_data_preset"
local flow_pie = {}
local values_table = {}
-- ##########################################
local function update_section(sections, section_ref, value)
local index = values_table[section_ref].index
local previous_value = values_table[section_ref].value
local new_value = previous_value + value
sections[index].label = section_ref .. " (" .. new_value .. ")"
sections[index].value = new_value
end
-- ##########################################
local function create_section(sections, section_ref, value)
local index = #sections + 1
sections[index] = {
label = section_ref .. " (" .. value .. ")",
value = value,
url = '#'
}
values_table[section_ref] = {
index = index,
value = value
}
end
-- ##########################################
local function format_table(sections, query, table, max_sections)
local remote_asn = {}
local others = {
label = i18n("others"),
value = 0
}
if query.only_costumers == true then
local as_utils = require "as_utils"
remote_asn = as_utils.getRemoteASNs()
end
for _, value in pairs(table or {}) do
local section_ref = value[query.section_ref]
local value_ref = tonumber(value[query.value_ref])
if query.only_costumers == nil or query.only_costumers == false or
(query.only_costumers == true and remote_asn[section_ref] ~= nil) then
if values_table[section_ref] ~= nil then
update_section(sections, section_ref, value_ref)
elseif #sections <= max_sections then
create_section(sections, section_ref, value_ref)
else
others.value = others.value + value_ref
end
end
end
if others.value > 0 then
if values_table["others"] ~= nil then
update_section(sections, "others", others.value)
else
create_section(sections, "others", others.value)
end
end
end
-- ##########################################
-- @brief Given a list of queries to be run, it will generate a pie
-- @param queries Queries to run
-- @return
function flow_pie.generatePie(queries, max_sections)
local sections = {}
for _, query in pairs(queries) do
local table_stats = flow_data.getStats({query})
format_table(sections, query, table_stats, max_sections)
end
return sections
end
-- ##########################################
return flow_pie

View file

@ -1509,7 +1509,7 @@ end
function validateSankeyAsCriteria(criteria)
return (criteria == 'as_transit_only_criteria' or criteria == 'ingress_egress_traffic_criteria'
or criteria == 'traffic_between_ases')
or criteria == 'traffic_between_ases' or criteria == 'user_traffic_breakdown')
end
-- #################################################################

View file

@ -0,0 +1,88 @@
--
-- (C) 2013-25 - ntop.org
--
dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path
require "check_redis_prefs"
require "flow_utils"
local rest_utils = require "rest_utils"
local flow_pie = require "flow_pie"
local format_utils = require "format_utils"
local graph_utils = require "graph_utils"
-- Retrieve the info from the rest
local asn = tonumber(_GET["asn"] or 0)
local ifid = _GET["ifid"] or interface.getId()
local criteria_as = _GET["criteria_as"]
local data_type = _GET["type"] or ""
local epoch_begin = nil
local epoch_end = nil
local res = {}
local filters = {}
local queries = {}
-- Empty ASN return an error
if isEmptyString(asn) or (asn == 0) then
rest_utils.answer(rest_utils.consts.err.invalid_args)
return
end
-- In case historical data has been requested, add the epoch_begin and epoch_end
if data_type == "historical" and hasClickHouseSupport() then
-- Handle the epoch only with the historical
epoch_begin = tonumber(_GET["epoch_begin"])
epoch_end = tonumber(_GET["epoch_end"])
end
if criteria_as == "user_traffic_breakdown" then
queries = {
{
select_query = {
"src_asn", "total_bytes"
},
rename_key_field = {"costumer"},
different_from = {nil, "src_asn", "dst_asn"},
skip_flow = {{key = "src_asn", value = "0"}},
where_query = {"dst_asn"},
sort_by = {"total_bytes"},
filters = {
dst_asn = asn,
ifid = ifid,
first_seen = epoch_begin,
last_seen = epoch_end
},
only_costumers = true,
value_ref = "total_bytes",
section_ref = "costumer"
}, {
select_query = {
"dst_asn", "total_bytes"
},
rename_key_field = {"costumer"},
where_query = {"src_asn"},
sort_by = {"total_bytes"},
different_from = {"src_asn", "dst_asn"},
skip_flow = {{key = "dst_asn", value = 0}},
filters = {
src_asn = asn,
ifid = ifid,
first_seen = epoch_begin,
last_seen = epoch_end
},
only_costumers = true,
value_ref = "total_bytes",
section_ref = "costumer"
}
}
end
local sections
sections = flow_pie.generatePie(queries, 10000)
table.sort(sections, function(a, b)
return a.value > b.value
end)
local js_formatter = "formatValue"
rest_utils.extended_answer(rest_utils.consts.success.ok, graph_utils.convert_pie_data(sections, true, js_formatter))