-- -- (C) 2013-15 - ntop.org -- top_rrds = { ["bytes.rrd"] = "Traffic", ["packets.rrd"] = "Packets", ["drops.rrd"] = "Packet Drops", ["num_flows.rrd"] = "Active Flows", ["num_hosts.rrd"] = "Active Hosts", ["num_http_hosts.rrd"] = "Active HTTP Servers" } -- ######################################################## if(ntop.isPro()) then package.path = dirs.installdir .. "/pro/scripts/lua/modules/?.lua;" .. package.path require "nv_graph_utils" end -- ######################################################## function navigatedir(url, label, base, path, go_deep, print_html) local shown = false local to_skip = false --print("
  • (d) "..path.."
  • \n") local ret = { } local do_debug = false rrds = ntop.readdir(path) table.sort(rrds) for k,v in pairsByKeys(rrds, asc) do if(v ~= nil) then p = fixPath(path .. "/" .. v) if(ntop.isdir(p)) then if(go_deep) then r = navigatedir(url, label.."/"..v, base, p, print_html) for k,v in pairs(r) do ret[k] = v if(do_debug) then print(v.."
    \n") end end end else if(top_rrds[v] == nil) then if(label == "*") then to_skip = true else if(not(shown) and not(to_skip)) then if(print_html) then print('\n') end end return(ret) end -- ######################################################## function breakdownBar(sent, sentLabel, rcvd, rcvdLabel) if((sent+rcvd) > 0) then sent2rcvd = round((sent * 100) / (sent+rcvd), 0) print('
    '..sentLabel) print('
    ' .. rcvdLabel .. '
    ') else print(' ') end end -- ######################################################## function percentageBar(total, value, valueLabel) if(total > 0) then pctg = round((value * 100) / total, 0) print('
    '..valueLabel) print('
    ') else print(' ') end end -- ######################################################## function getRRDName(ifid, host, rrdFile) rrdname = fixPath(dirs.workingdir .. "/" .. ifid .. "/rrd/") if(host ~= nil) then rrdname = rrdname .. getPathFromKey(host) .. "/" end return(rrdname .. rrdFile) end -- ######################################################## zoom_vals = { { "1m", "now-60s", 60 }, { "5m", "now-300s", 60*5 }, { "10m", "now-600s", 60*10 }, { "1h", "now-1h", 60*60*1 }, { "3h", "now-3h", 60*60*3 }, { "6h", "now-6h", 60*60*6 }, { "12h", "now-12h", 60*60*12 }, { "1d", "now-1d", 60*60*24 }, { "1w", "now-1w", 60*60*24*7 }, { "2w", "now-2w", 60*60*24*14 }, { "1M", "now-1mon", 60*60*24*31 }, { "6M", "now-6mon", 60*60*24*31*6 }, { "1Y", "now-1y", 60*60*24*366 } } function getZoomAtPos(cur_zoom, pos_offset) local pos = 1 local new_zoom_level = cur_zoom for k,v in pairs(zoom_vals) do if(zoom_vals[k][1] == cur_zoom) then if (pos+pos_offset >= 1 and pos+pos_offset < 13) then new_zoom_level = zoom_vals[pos+pos_offset][1] break end end pos = pos + 1 end return new_zoom_level end -- ######################################################## function getZoomDuration(cur_zoom) for k,v in pairs(zoom_vals) do if(zoom_vals[k][1] == cur_zoom) then return(zoom_vals[k][3]) end end return(180) end -- ######################################################## function drawPeity(ifid, host, rrdFile, zoomLevel, selectedEpoch) rrdname = getRRDName(ifid, host, rrdFile) if(zoomLevel == nil) then zoomLevel = "1h" end nextZoomLevel = zoomLevel; epoch = tonumber(selectedEpoch); for k,v in ipairs(zoom_vals) do if(zoom_vals[k][1] == zoomLevel) then if(k > 1) then nextZoomLevel = zoom_vals[k-1][1] end if(epoch) then start_time = epoch - zoom_vals[k][3]/2 end_time = epoch + zoom_vals[k][3]/2 else start_time = zoom_vals[k][2] end_time = "now" end end end --print("=> Found "..rrdname.."

    \n") if(ntop.notEmptyFile(rrdname)) then --io.write("=> Found ".. start_time .. "|" .. end_time .. "

    \n") local fstart, fstep, fnames, fdata = ntop.rrd_fetch(rrdname, 'AVERAGE', start_time..", end_time..") local max_num_points = 512 -- This is to avoid having too many points and thus a fat graph local num_points_found = table.getn(fdata) local sample_rate = round(num_points_found / max_num_points) local num_points = 0 local step = 1 local series = {} if(sample_rate < 1) then sample_rate = 1 end -- print("=> "..num_points_found.."[".. sample_rate .."]["..fstart.."]

    ") id = 0 num = 0 total = 0 sample_rate = sample_rate-1 points = {} for i, v in ipairs(fdata) do timestamp = fstart + (i-1)*fstep num_points = num_points + 1 local elemId = 1 for _, w in ipairs(v) do if(w ~= w) then -- This is a NaN v = 0 else v = tonumber(w) if(v < 0) then v = 0 end end value = v*8 -- bps total = total + value if(id == sample_rate) then points[num] = round(value).."" num = num+1 id = 0 else id = id + 1 end elemId = elemId + 1 end end end print(""..round(total).." ") for i=0,10 do if(i > 0) then print(",") end print(points[i]) end print("\n") end -- ######################################################## function drawRRD(ifid, host, rrdFile, zoomLevel, baseurl, show_timeseries, selectedEpoch, selected_epoch_sanitized, topArray) local debug_rrd = false if(zoomLevel == nil) then zoomLevel = "1h" end if(ntop.isPro()) then drawProGraph(ifid, host, rrdFile, zoomLevel, baseurl, show_timeseries, selectedEpoch, selected_epoch_sanitized, topArray) return end dirs = ntop.getDirs() rrdname = getRRDName(ifid, host, rrdFile) names = {} series = {} if(zoomLevel == nil) then zoomLevel = "1h" end nextZoomLevel = zoomLevel; epoch = tonumber(selectedEpoch); for k,v in ipairs(zoom_vals) do if(zoom_vals[k][1] == zoomLevel) then if(k > 1) then nextZoomLevel = zoom_vals[k-1][1] end if(epoch) then start_time = epoch - zoom_vals[k][3]/2 end_time = epoch + zoom_vals[k][3]/2 else start_time = zoom_vals[k][2] end_time = "now" end end end local maxval_bits_time = 0 local maxval_bits = 0 local minval_bits = 0 local minval_bits_time = 0 local lastval_bits = 0 local lastval_bits_time = 0 local total_bytes = 0 local num_points = 0 local step = 1 prefixLabel = l4Label(string.gsub(rrdFile, ".rrd", "")) -- io.write(prefixLabel.."\n") if(prefixLabel == "Bytes") then prefixLabel = "Traffic" end if(ntop.notEmptyFile(rrdname)) then -- print("=> Found "..rrdname.."

    \n") -- print("=> "..rrdname) -- io.write("=> *** ".. start_time .. "|" .. end_time .. "

    \n") local fstart, fstep, fnames, fdata = ntop.rrd_fetch(rrdname, 'AVERAGE', start_time, end_time) --print("=> here we go") local max_num_points = 600 -- This is to avoid having too many points and thus a fat graph local num_points_found = table.getn(fdata) local sample_rate = round(num_points_found / max_num_points) if(sample_rate < 1) then sample_rate = 1 end -- DEBUG --tprint(fdata, 1) step = fstep num = 0 names_cache = {} for i, n in ipairs(fnames) do -- handle duplicates if (names_cache[n] == nil) then names_cache[n] = true names[num] = prefixLabel if(host ~= nil) then names[num] = names[num] .. " (" .. firstToUpper(n)..")" end num = num + 1 --io.write(prefixLabel.."\n") --print(num.."\n") end end id = 0 sampling = 0 --sample_rate = 1 sample_rate = sample_rate-1 accumulated = 0 for i, v in ipairs(fdata) do s = {} s[0] = fstart + (i-1)*fstep num_points = num_points + 1 local elemId = 1 for _, w in ipairs(v) do if(w ~= w) then -- This is a NaN v = 0 else --io.write(w.."\n") v = tonumber(w) if(v < 0) then v = 0 end end if(v > 0) then lastval_bits_time = s[0] lastval_bits = v end s[elemId] = v*8 -- bps --if(s[elemId] > 0) then io.write("[".. elemId .. "]=" .. s[elemId] .."\n") end elemId = elemId + 1 end total_bytes = total_bytes + v*fstep --if((v*fstep) > 0) then io.write(" | " .. (v*fstep) .." | [sampling: ".. sampling .. "/" .. sample_rate.."]\n") end if(sampling == sample_rate) then if(sample_rate > 0) then s[1] = accumulated / sample_rate end series[id] = s id = id + 1 sampling = 0 accumulated = 0 else accumulated = accumulated + s[1] sampling = sampling + 1 end end for key, value in pairs(series) do local t = 0 for elemId=0,(num-1) do --io.write(key.."="..value[elemId+1].. "\n") t = t + value[elemId+1] -- bps end t = t * step if(((minval_bits_time == 0) or (minval_bits >= t)) and (value[0] < lastval_bits_time)) then --io.write(value[0].."\t".. t .. "\t".. lastval_bits_time .. "\n") minval_bits_time = value[0] minval_bits = t end if((maxval_bits_time == 0) or (maxval_bits <= t)) then maxval_bits_time = value[0] maxval_bits = t end end print [[

    ]] printGraphTopFlows(ifid, (host or ''), _GET["epoch"], zoomLevel, rrdFile) print [[
    ]] if(show_timeseries == 1) then print [[
    ]] end -- show_timeseries == 1 print(' Timeframe:
    \n') for k,v in ipairs(zoom_vals) do print('\n') end print [[

    NOTE: Click on the graph to zoom.

    ]] if(string.contains(rrdFile, "num_")) then formatter_fctn = "fint" else formatter_fctn = "fpackets" end if (topArray ~= nil) then print [[ ]] print(' \n') if(string.contains(rrdFile, "num_") or string.contains(rrdFile, "packets") or string.contains(rrdFile, "drops")) then print(' \n') print(' \n') print(' \n') print(' \n') print(' \n') else formatter_fctn = "fbits" print(' \n') print(' \n') print(' \n') print(' \n') print(' \n') end print(' \n') print(' \n') print [[
     TimeValue
    Min' .. os.date("%x %X", minval_bits_time) .. '' .. formatValue(round(minval_bits/step), 1) .. '
    Max' .. os.date("%x %X", maxval_bits_time) .. '' .. formatValue(round(maxval_bits/step), 1) .. '
    Last' .. os.date("%x %X", last_time) .. '' .. formatValue(round(lastval_bits/step), 1) .. '
    Average' .. formatValue(round(total_bytes*8/(step*num_points), 2)) .. '
    Total Number' .. formatValue(round(total_bytes)) .. '
    Min' .. os.date("%x %X", minval_bits_time) .. '' .. bitsToSize(minval_bits/step) .. '
    Max' .. os.date("%x %X", maxval_bits_time) .. '' .. bitsToSize(maxval_bits/step) .. '
    Last' .. os.date("%x %X", last_time) .. '' .. bitsToSize(lastval_bits/step) .. '
    Average' .. bitsToSize(total_bytes*8/(step*num_points)) .. '
    Total Traffic' .. bytesToSize(total_bytes) .. '
    Selection Time
    Minute
    Top Talkers
    ]] end -- topArray ~= nil print[[
    ]] print [[ ]] else print("
    File "..rrdname.." cannot be found
    ") end end -- ######################################################## function create_rrd(name, step, ds) if(not(ntop.exists(name))) then if(enable_second_debug == 1) then io.write('Creating RRD ', name, '\n') end local prefs = ntop.getPrefs() ntop.rrd_create( name, step, -- step 'DS:' .. ds .. ':DERIVE:5:U:U', 'RRA:AVERAGE:0.5:1:'..tostring(prefs.intf_rrd_raw_days*24*60*60), -- raw: 1 day = 86400 'RRA:AVERAGE:0.5:60:'..tostring(prefs.intf_rrd_1min_days*24*60), -- 1 min resolution = 1 month 'RRA:AVERAGE:0.5:3600:'..tostring(prefs.intf_rrd_1h_days*24), -- 1h resolution (3600 points) 2400 hours = 100 days 'RRA:AVERAGE:0.5:86400:'..tostring(prefs.intf_rrd_1d_days) -- 1d resolution (86400 points) 365 days -- 'RRA:HWPREDICT:1440:0.1:0.0035:20' ) end end function create_rrd_num(name, ds) if(not(ntop.exists(name))) then if(enable_second_debug == 1) then io.write('Creating RRD ', name, '\n') end local prefs = ntop.getPrefs() ntop.rrd_create( name, 1, -- step 'DS:' .. ds .. ':GAUGE:5:0:U', 'RRA:AVERAGE:0.5:1:'..tostring(prefs.intf_rrd_raw_days*24*60*60), -- raw: 1 day = 86400 'RRA:AVERAGE:0.5:3600:'..tostring(prefs.intf_rrd_1h_days*24), -- 1h resolution (3600 points) 2400 hours = 100 days 'RRA:AVERAGE:0.5:86400:'..tostring(prefs.intf_rrd_1d_days) -- 1d resolution (86400 points) 365 days -- 'RRA:HWPREDICT:1440:0.1:0.0035:20' ) end end function makeRRD(basedir, ifname, rrdname, step, value) name = fixPath(basedir .. "/" .. rrdname .. ".rrd") if(string.contains(rrdname, "num_")) then create_rrd_num(name, rrdname) else create_rrd(name, 1, rrdname) end ntop.rrd_update(name, "N:".. toint(value)) if(enable_second_debug == 1) then io.write('Updating RRD ['.. ifname..'] '.. name .. " " .. value ..'\n') end end function createRRDcounter(path, step, verbose) if(not(ntop.exists(path))) then if(verbose) then print('Creating RRD ', path, '\n') end local prefs = ntop.getPrefs() ntop.rrd_create( path, step, -- step 'DS:sent:DERIVE:600:U:U', 'DS:rcvd:DERIVE:600:U:U', 'RRA:AVERAGE:0.5:1:'..tostring(prefs.other_rrd_raw_days*24*300), -- raw: 1 day = 1 * 24 = 24 * 300 sec = 7200 'RRA:AVERAGE:0.5:12:'..tostring(prefs.other_rrd_1h_days*24), -- 1h resolution (12 points) 2400 hours = 100 days 'RRA:AVERAGE:0.5:288:'..tostring(prefs.other_rrd_1d_days) -- 1d resolution (288 points) 365 days --'RRA:HWPREDICT:1440:0.1:0.0035:20' ) end end -- ######################################################## function createSingleRRDcounter(path, verbose) if(not(ntop.exists(path))) then if(verbose) then print('Creating RRD ', path, '\n') end local prefs = ntop.getPrefs() ntop.rrd_create( path, 300, -- step 'DS:num:DERIVE:600:U:U', 'RRA:AVERAGE:0.5:1:'..tostring(prefs.other_rrd_raw_days*24*300), -- raw: 1 day = 1 * 24 = 24 * 300 sec = 7200 'RRA:AVERAGE:0.5:12:'..tostring(prefs.other_rrd_1h_days*24), -- 1h resolution (12 points) 2400 hours = 100 days 'RRA:AVERAGE:0.5:288:'..tostring(prefs.other_rrd_1d_days), -- 1d resolution (288 points) 365 days 'RRA:HWPREDICT:1440:0.1:0.0035:20') end end -- ######################################################## function dumpSingleTreeCounters(basedir, label, host, verbose) what = host[label] if(what ~= nil) then for k,v in pairs(what) do for k1,v1 in pairs(v) do -- print("-->"..k1.."/".. type(v1).."<--\n") if(type(v1) == "table") then for k2,v2 in pairs(v1) do dname = fixPath(basedir.."/"..label.."/"..k.."/"..k1) if(not(ntop.exists(dname))) then ntop.mkdir(dname) end fname = dname..fixPath("/"..k2..".rrd") createSingleRRDcounter(fname, verbose) ntop.rrd_update(fname, "N:"..toint(v2)) if(verbose) then print("\t"..fname.."\n") end end else dname = fixPath(basedir.."/"..label.."/"..k) if(not(ntop.exists(dname))) then ntop.mkdir(dname) end fname = dname..fixPath("/"..k1..".rrd") createSingleRRDcounter(fname, verbose) ntop.rrd_update(fname, "N:"..toint(v1)) if(verbose) then print("\t"..fname.."\n") end end end end end end function printGraphTopFlows(ifId, host, epoch, zoomLevel, l7proto) -- Check if the DB is enabled rsp = interface.execSQLQuery("show tables") if(rsp == nil) then return end if((epoch == nil) or (epoch == "")) then epoch = os.time() end local d = getZoomDuration(zoomLevel)/2 epoch_end = epoch+d epoch_begin = epoch-d url_update = "/lua/get_db_flows.lua?ifId="..ifId.. "&host="..(host or '') .. "&epoch_begin="..epoch_begin.."&epoch_end="..epoch_end title = "Top Flows" if(l7proto ~= nil) then local id if(string.ends(l7proto, ".rrd")) then l7proto = string.sub(l7proto, 1, -5) end id = interface.getnDPIProtoId(l7proto) if(id ~= -1) then url_update = url_update .. "&l7proto="..id title = "Top "..l7proto.." Flows" end end title = title .. " ["..formatEpoch(epoch_begin).." - "..formatEpoch(epoch_end).."]" print [[
    ]] end