EVOLUTION-MANAGER
Edit File: flows_stats.lua
-- -- (C) 2013-24 - ntop.org -- -- trace_script_duration = true local dirs = ntop.getDirs() package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path local ifstats = interface.getStats() if (ifstats.has_seen_pods or ifstats.has_seen_containers) then -- Use a different flows page dofile(dirs.installdir .. "/scripts/lua/inc/ebpf_flows_stats.lua") return end require "lua_utils" require "flow_utils" local page_utils = require("page_utils") local template = require "template_utils" local have_nedge = ntop.isnEdge() sendHTTPContentTypeHeader('text/html') page_utils.print_header_and_set_active_menu_entry(ternary(have_nedge, page_utils.menu_entries.nedge_flows, page_utils.menu_entries.active_flows)) dofile(dirs.installdir .. "/scripts/lua/inc/menu.lua") local draw = _GET["draw"] or 0 local sort = _GET["sort"] or "flows" local order = _GET["order"] or "desc" local start = _GET["start"] or 0 local length = _GET["length"] or 10 local page = _GET["page"] local client = _GET["client"] local server = _GET["server"] local flow_info = _GET["flow_info"] local aggregation_criteria = _GET["aggregation_criteria"] or "client_server_srv_port_app_proto" local base_url = ntop.getHttpPrefix() .. "/lua/flows_stats.lua" local page_params = { ifid = interface.getId(), client = client, server = server, flow_info = flow_info } page_utils.print_navbar(i18n('graphs.active_flows'), base_url .. "?", {{ active = page == "flows" or page == nil, url = base_url .. "?page=flows&traffic_type=unicast", page_name = "flows", label = "<i class=\"fas fa-lg fa-home\"></i>" }, { url = base_url .. "?page=analysis&aggregation_criteria=" .. aggregation_criteria .. "&draw=" .. draw .. "&sort=" .. sort .. "&order=" .. order .. "&start=" .. start .. "&length=" .. length, active = page == "analysis", page_name = "analysis", label = i18n("analysis") }}) if ((page == "flows" or page == nil) and ntop.isnEdge()) then -- nDPI application and category local application = _GET["application"] if (application ~= nil) then local application_split = string.split(application, "%.") if application_split and #application_split == 2 then -- 5.26 else local _application = tonumber(application) if (_application) then application = interface.getnDPIProtoName(_application) end end end local category = _GET["category"] local hosts = _GET["hosts"] local host = _GET["host"] local talking_with = _GET["talkingWith"] local vhost = _GET["vhost"] local flowhosts_type = _GET["flowhosts_type"] local ipversion = _GET["version"] local l4proto = _GET["l4proto"] local vlan = _GET["vlan"] local icmp_type = _GET["icmp_type"] local icmp_code = _GET["icmp_cod"] local dscp_filter = _GET["dscp"] local host_pool = _GET["host_pool_id"] local traffic_profile = _GET["traffic_profile"] -- remote exporters address and interfaces local deviceIP = _GET["deviceIP"] local inIfIdx = _GET["inIfIdx"] local outIfIdx = _GET["outIfIdx"] local traffic_type = _GET["traffic_type"] or "unicast" local alert_type = _GET["alert_type"] local alert_type_severity = _GET["alert_type_severity"] local tcp_state = _GET["tcp_flow_state"] local port = _GET["port"] local network_id = _GET["network"] local prefs = ntop.getPrefs() local duration_or_last_seen = prefs.flow_table_time local begin_epoch_set = (ntop.getPref("ntopng.prefs.first_seen_set") == "1") local flows_filter = getFlowsFilter() flows_filter.statusFilter = nil -- remove the filter, otherwise no menu entries will be shown local flowstats = interface.getActiveFlowsStats(host, flows_filter, false, talking_with, client, server, flow_info) local active_msg = getFlowsTableTitle(ntop.getHttpPrefix()) local mini_title = i18n("flow_details.purge_time", { purge_time = ntop.getPref("ntopng.prefs.flow_max_idle"), prefs_url = ntop.getHttpPrefix() .. '/lua/admin/prefs.lua?tab=in_memory' }) if (category ~= nil) then page_params["category"] = category end if (application ~= nil) then page_params["application"] = application end if (host ~= nil) then page_params["host"] = host end if (port ~= nil) then page_params["port"] = port end if (vhost ~= nil) then page_params["vhost"] = vhost end if (hosts ~= nil) then page_params["hosts"] = hosts end if (port ~= nil) then page_params["port"] = port end if (ipversion ~= nil) then page_params["version"] = ipversion end if (l4proto ~= nil) then page_params["l4proto"] = l4proto end if (deviceIP ~= nil) then page_params["deviceIP"] = deviceIP end if (inIfIdx ~= nil) then page_params["inIfIdx"] = inIfIdx end if (outIfIdx ~= nil) then page_params["outIfIdx"] = outIfIdx end if (vlan ~= nil) then page_params["vlan"] = vlan end if (traffic_type ~= nil) then page_params["traffic_type"] = traffic_type end if (alert_type ~= nil) then page_params["alert_type"] = alert_type end if (alert_type_severity ~= nil) then page_params["alert_type_severity"] = alert_type_severity end if (tcp_state ~= nil) then page_params["tcp_flow_state"] = tcp_state end if (network_id ~= nil) then page_params["network"] = network_id end if (flowhosts_type ~= nil) then page_params["flowhosts_type"] = flowhosts_type end if ((icmp_type ~= nil) and (icmp_code ~= nil)) then page_params["icmp_type"] = icmp_type page_params["icmp_cod"] = icmp_code end if (dscp_filter ~= nil) then page_params["dscp"] = dscp_filter end if (host_pool ~= nil) then page_params["host_pool_id"] = host_pool end if (traffic_profile ~= nil) then page_params["traffic_profile"] = traffic_profile end local is_chart_printed = false print [[<div class="d-flex m-1">]] if is_chart_printed then print [[<h3 class="m-auto">]] else print [[<h3 class="me-auto mt-auto mb-auto">]] end print(active_msg) print [[</h3>]] if (table.len(page_params) > 0) and (not isEmptyString(page_params["application"])) then is_chart_printed = true print [[ <div class="col-5"> <div class="info-stats"> <ul class="nav-side m-0 ps-5 ms-1" style="list-style-type: none;"> <li class="nav-item"> <div class="up"> <i class="fas fa-arrow-up" data-original-title="" title=""></i> <span id="upload-filter-traffic-chart" class="line">0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</span> <span class='d-inline-block text-end' style='width: 13ch'> <span id="upload-filter-traffic-value">0 kbit/s</span> | </span> <span id="filtered-flows-tot-bytes">]] print(i18n("flows_page.tot_bytes")) print [[</span> <span id="filtered-flows-tot-bytes-value">0 B</span> </div> </li> <li class="nav-item"> <div class="down"> <i class="fas fa-arrow-down" data-original-title="" title=""></i> <span id="download-filter-traffic-chart" class="line">0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</span> <span class='d-inline-block text-end' style='width: 13ch'> <span id="download-filter-traffic-value">0 kbit/s</span> | </span> <span id="filtered-flows-tot-throughput">]] print(i18n("flows_page.tot_throughput")) print [[</span> <span id="filtered-flows-tot-throughput-value">0 kbit/s</span> </div> </li> </ul> </div> </div> ]] end print [[<h6 class="ms-auto mt-auto mb-auto">]] print(mini_title) print [[</h6>]] print [[</div>]] print [[ <div id="table-flows"></div> <script> var url_update = "]] print(getPageUrl(ntop.getHttpPrefix() .. "/lua/get_flows_data.lua", page_params)) print('";') print [[ var table = $("#table-flows").datatable({ url: url_update , tableCallback: function(test_tmp) { ]] initFlowsRefreshRows() print [[ }, ]] preference = tablePreferences("rows_number", _GET["perPage"]) if (preference ~= "") then print('perPage: ' .. preference .. ",\n") end print(" title: \"") print [[", showFilter: true, showPagination: true, ]] -- Automatic default sorted. NB: the column must be exists. print('sort: [ ["' .. getDefaultTableSort("flows") .. '","' .. getDefaultTableSortOrder("flows") .. '"] ],\n') print('buttons: [') printActiveFlowsDropdown(base_url, page_params, ifstats, flowstats) print(" ],\n") print [[ columns: [ { title: "", field: "key", hidden: true, }, { title: "", field: "hash_id", hidden: true, }, { title: "]] print(i18n("serial")) print [[", field: "column_key", /* This is the serial number but called key for placing the flow button pointing to the flow key */ sortable: true, css: { textAlign: 'center', whiteSpace: 'nowrap' } }, { title: "]] print(i18n("application")) print [[", field: "column_ndpi", sortable: true, css: { textAlign: 'left', whiteSpace: 'nowrap' } }, { title: "]] print(i18n("proto")) print [[", field: "column_proto_l4", sortable: true, css: { textAlign: 'left', whiteSpace: 'nowrap' } }, ]] print [[ { title: "]] print(i18n("client")) print [[", field: "column_client", sortable: true, css: { whiteSpace: 'nowrap' } }, { title: "]] print(i18n("server")) print [[", field: "column_server", sortable: true, css: { whiteSpace: 'nowrap' } }, ]] if begin_epoch_set == true then print [[ { title: "]] print(i18n("first_seen")) print [[", field: "column_first_seen", sortable: true, css: { whiteSpace: 'nowrap', textAlign: 'center', } }, ]] end if duration_or_last_seen == false then print [[ { title: "]] print(i18n("duration")) print [[", field: "column_duration", sortable: true, css: { whiteSpace: 'nowrap', textAlign: 'center', } }, ]] else print [[ { title: "]] print(i18n("last_seen")) print [[", field: "column_last_seen", sortable: true, css: { whiteSpace: 'nowrap', textAlign: 'center' } }, ]] end print [[{ title: "]] print(i18n("score")) print [[", field: "column_score", hidden: ]] print(ternary(isScoreEnabled(), "false", "true")) print [[, sortable: true, css: { textAlign: 'center', whiteSpace: 'nowrap' } }, { title: "]] print(i18n("breakdown")) print [[", field: "column_breakdown", sortable: false, css: { textAlign: 'center', whiteSpace: 'nowrap' } }, { title: "]] print(i18n("flows_page.actual_throughput")) print [[", field: "column_thpt", sortable: true, css: { textAlign: 'right', whiteSpace: 'nowrap' } }, { title: "]] print(i18n("flows_page.total_bytes")) print [[", field: "column_bytes", sortable: true, css: { textAlign: 'right', whiteSpace: 'nowrap' } }, { title: "]] print(i18n("info")) print [[", field: "column_info", sortable: false, css: { textAlign: 'left', whiteSpace: 'nowrap' } },]] if interface.isPacketInterface() == false then print [[ { title: "]] print(i18n('flow_devices.exporter_ip')) print [[", field: "column_device_ip", sortable: true, css: { textAlign: 'left', whiteSpace: 'nowrap' } }, { title: "]] print(i18n('flows_page.inIfIdx')) print [[", field: "column_in_index", sortable: true, css: { textAlign: 'left', whiteSpace: 'nowrap' } }, { title: "]] print(i18n('flows_page.outIfIdx')) print [[", field: "column_out_index", sortable: true, css: { textAlign: 'left', whiteSpace: 'nowrap' } }, ]] end print [[ ] }); ]] if (have_nedge) then printBlockFlowJs() end print [[ </script> ]] if (table.len(page_params) > 0) and (not isEmptyString(page_params["application"])) then print([[ <script type='text/javascript'> let old_totBytesSent = 0; let old_totBytesRcvd = 0; let refresh_rate = 5; /* seconds */ $(document).ready(function() { const downloadChart = $("#download-filter-traffic-chart").peity("line", { width: 64, fill: "lightgreen" }); const uploadChart = $("#upload-filter-traffic-chart").peity("line", { width: 64 }); function pushNewValue(chart, newValue) { const values = chart.text().split(","); values.shift(); values.push(newValue); chart .text(values.join(",")) .change() } function updateChart() { const request = $.get("]] .. getPageUrl(ntop.getHttpPrefix() .. "/lua/rest/v2/get/flow/traffic_stats.lua", page_params) .. "&ifid=" .. interface.getId() .. [["); request.then((data) => { let throughput_bps_sent = (8 * (data.rsp.totBytesSent - old_totBytesSent)) / refresh_rate; let throughput_bps_rcvd = (8 * (data.rsp.totBytesRcvd - old_totBytesRcvd)) / refresh_rate; if (throughput_bps_sent < 0) throughput_bps_sent = 0; if (throughput_bps_rcvd < 0) throughput_bps_rcvd = 0; let tot_throughput = (throughput_bps_sent + throughput_bps_rcvd) || 0; if ((old_totBytesSent > 0) || (old_totBytesRcvd > 0)) { /* Second iteration or later */ pushNewValue(downloadChart, -throughput_bps_rcvd); pushNewValue(uploadChart, throughput_bps_sent); $('#download-filter-traffic-value').html(NtopUtils.bitsToSize(throughput_bps_rcvd, 1000)); $('#upload-filter-traffic-value').html(NtopUtils.bitsToSize(throughput_bps_sent, 1000)); $('#filtered-flows-tot-throughput-value').html(NtopUtils.bitsToSize(tot_throughput, 1000)); } /* Keep the old value for computing the differnce at the next round */ old_totBytesSent = data.rsp.totBytesSent || 0; old_totBytesRcvd = data.rsp.totBytesRcvd || 0; $('#filtered-flows-tot-bytes-value').html(NtopUtils.bytesToSize(old_totBytesSent + old_totBytesRcvd)); }) } setInterval(() => { updateChart() }, refresh_rate*1000); updateChart(); }) </script> ]]) end elseif (page == "flows" or page == nil) then local has_exporters = false if ntop.isPro() and interface.isPacketInterface() == false then local flowdevs = interface.getFlowDevices() or {} if table.len(flowdevs) > 0 then has_exporters = true end end local json = require "dkjson" local json_context = json.encode({ ifid = ifstats.id, has_exporters = has_exporters, is_viewed = interface.isViewed(), is_clickhouse_enabled = hasClickHouseSupport(), is_pcap = interface.isPcapDumpInterface(), csrf = ntop.getRandomCSRFValue() }) template.render("pages/vue_page.template", { vue_page_name = "PageFlowsList", page_context = json_context }) else -- Analysis local json = require 'dkjson' -- Format VLANs dropdown local tmp_vlans = {} local vlans = {} local vlan_list = interface.getVLANsList() or {} if table.len(vlan_list) > 0 then vlan_list = vlan_list.VLANs end for _, vlan_info in pairsByField(vlan_list or {}, 'vlan_id', asc) do local label = i18n("hosts_stats.vlan_title", { vlan = getFullVlanName(vlan_info.vlan_id) }) local currently_active = false if vlan_info.vlan_id == 0 then label = i18n('no_vlan') end tmp_vlans[#tmp_vlans + 1] = { label = label, id = vlan_info.vlan_id, countable = false, key = vlan_info.vlan_id, currently_active = (vlan == vlan_info.vlan_id or currently_active) } end if (#tmp_vlans > 1) then local currently_active = false tmp_vlans[#tmp_vlans + 1] = { label = i18n("flows_page.all_vlan_ids"), id = -1, countable = false, key = -1, currently_active = (vlan == -1 or currently_active) } end -- Order again by name for _, vlan in pairsByField(tmp_vlans or {}, 'label', asc_insensitive) do vlans[#vlans + 1] = vlan end local context = { ifid = ifId, vlans = json.encode(vlans), aggregation_criteria = aggregation_criteria, is_ntop_enterprise_m = ntop.isEnterpriseM(), draw = draw, sort = sort, order = order, start = start, length = length, host = "", csrf = ntop.getRandomCSRFValue() } local json_context = json.encode(context) template.render("pages/vue_page.template", { vue_page_name = "PageAggregatedLiveFlows", page_context = json_context }) end dofile(dirs.installdir .. "/scripts/lua/inc/footer.lua")