diff --git a/include/Ntop.h b/include/Ntop.h index 56ff1a3055..efe332385f 100644 --- a/include/Ntop.h +++ b/include/Ntop.h @@ -355,6 +355,7 @@ class Ntop { inline NagiosManager* getNagios() { return(nagios_manager); }; #endif #endif + void checkSNMPDeviceAlerts(ScriptPeriodicity p); void lua_periodic_activities_stats(NetworkInterface *iface, lua_State* vm); void getUsers(lua_State* vm); bool isUserAdministrator(lua_State* vm); diff --git a/scripts/callbacks/alert_defs/alert_port_load_threshold_exceeded.lua b/scripts/callbacks/alert_defs/alert_port_load_threshold_exceeded.lua index bb61f228e6..a27d0b1b25 100644 --- a/scripts/callbacks/alert_defs/alert_port_load_threshold_exceeded.lua +++ b/scripts/callbacks/alert_defs/alert_port_load_threshold_exceeded.lua @@ -5,13 +5,17 @@ local function snmpPortLoadThresholdFormatter(ifid, alert, info) if ntop.isPro() then require "snmp_utils" end - return(i18n("alerts_dashboard.snmp_port_load_threshold_exceeded_message", - {device = info.device, + local fmt = { + device = info.device, port = info.interface_name or info.interface, url = snmpDeviceUrl(info.device), port_url = snmpIfaceUrl(info.device, info.interface), - port_load = info.interface_load, - direction = ternary(info.interface_load, "RX", "TX")})) + in_load = info.in_load, + out_load = info.out_load, + threshold = info.load_threshold, + } + + return(i18n("alerts_dashboard.snmp_port_load_threshold_exceeded_message", fmt)) end -- ####################################################### diff --git a/scripts/callbacks/system/snmp_device.lua b/scripts/callbacks/system/snmp_device.lua new file mode 100644 index 0000000000..43f8956754 --- /dev/null +++ b/scripts/callbacks/system/snmp_device.lua @@ -0,0 +1,100 @@ +-- +-- (C) 2019 - ntop.org +-- + +local dirs = ntop.getDirs() +package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path +require "lua_utils" +require "alert_utils" +require "snmp_utils" + +local alerts_api = require("alerts_api") +local user_scripts = require("user_scripts") +local alert_consts = require("alert_consts") + +local do_benchmark = true -- Compute benchmarks and store their results +local do_print_benchmark = false -- Print benchmarks results to standard output +local do_trace = false -- Trace lua calls + +local config_alerts = nil +local available_modules = nil +local ifid = nil +local snmp_device_entity = alert_consts.alert_entities.snmp_device.entity_id + +-- The function below ia called once (#pragma once) +function setup(str_granularity) + if do_trace then print("alert.lua:setup("..str_granularity..") called\n") end + + interface.select(getSystemInterfaceId()) + ifid = interface.getId() + local ifname = getInterfaceName(tostring(ifid)) + + -- Load the threshold checking functions + available_modules = user_scripts.load(user_scripts.script_types.snmp_device, ifid, "snmp_device", nil --[[ load all hooks --]], nil, do_benchmark) + + -- config_alerts = getNetworksConfiguredAlertThresholds(ifname, str_granularity, available_modules.modules) +end + +-- ################################################################# + +-- The function below ia called once (#pragma once) +function teardown(str_granularity) + if(do_trace) then print("alert.lua:teardown("..str_granularity..") called\n") end + + user_scripts.teardown(available_modules, do_benchmark, do_print_benchmark) +end + +-- ################################################################# + +local cur_granularity + +local function snmp_device_interfaces_check_alerts(snmp_device, deadline) + local do_call = true + local granularity = cur_granularity + + local device_ip = snmp_device.get_device_info()["host"] + local device_interfaces = snmp_device.get_device()["interfaces"] or {} + local device_if_status = snmp_device.get_device()["interfaces_status"] or {} + local device_counters = snmp_device.get_device()["counters"] or {} + local device_bridge = snmp_device.get_device()["bridge"] or {} + + -- For each callback that needs to be called on the interfaces... + for mod_key, hook_fn in pairs(available_modules.hooks["snmpDeviceInterface"]) do + local check = available_modules.modules[mod_key] + + -- For each interface of the current device... + for snmp_interface_index, snmp_interface in pairs(device_interfaces) do + local entity_info = alerts_api.snmpInterfaceEntity(device_ip, snmp_interface_index) + local info = { + snmp_device_ip = device_ip, + snmp_interface = snmp_interface, + if_status = device_if_status[snmp_interface_index], + if_counters = device_counters[snmp_interface_index], + if_bridge = device_bridge[snmp_interface_index]} + + if(do_call) then + hook_fn({ + granularity = granularity, + alert_entity = entity_info, + entity_info = info, + cur_alerts = cur_alerts, + alert_config = config, + user_script = check, + }) + end + end + end + + return true +end + +-- ################################################################# + +-- The function below is called once per local snmp_device +function checkAlerts(granularity) + cur_granularity = granularity + + if not table.empty(available_modules.hooks["snmpDeviceInterface"]) then + local in_time = foreachSNMPDevice(snmp_device_interfaces_check_alerts, nil --[[ snmp_rrds_enabled --]], nil --[[ deadline --]]) + end +end diff --git a/scripts/locales/en.lua b/scripts/locales/en.lua index b3f5e69784..d6b2ecc81f 100644 --- a/scripts/locales/en.lua +++ b/scripts/locales/en.lua @@ -381,7 +381,7 @@ local lang = { ["snmp_port_errors"] = "Interface Errors", ["snmp_port_errors_increased"] = "Discard/error counters increased on interface %{port} on SNMP device %{device}", ["snmp_port_load_threshold_exceeded"] = "Interface Load Threshold Exceeded", - ["snmp_port_load_threshold_exceeded_message"] = "%{direction} load is %{port_load}%% on interface %{port} on SNMP device %{device}", + ["snmp_port_load_threshold_exceeded_message"] = "Load threshold exceeded on interface %{port} on SNMP device %{device} [threshold: %{threshold}%%][IN load: %{in_load}%%][OUT load: %{out_load}%%]", ["snmp_port_status_change"] = "Interface Status Change", ["starting_on"] = "starting on", ["submit"] = "Update Dashboard", diff --git a/scripts/lua/modules/alert_utils.lua b/scripts/lua/modules/alert_utils.lua index 516fd4e090..18657835d0 100644 --- a/scripts/lua/modules/alert_utils.lua +++ b/scripts/lua/modules/alert_utils.lua @@ -2873,39 +2873,6 @@ local function notify_ntopng_status(started) return(alerts_api.store(entity_info, type_info)) end -function notify_snmp_device_interface_status_change(snmp_host, snmp_interface) - local entity_info = alerts_api.snmpInterfaceEntity(snmp_host, snmp_interface["index"]) - local type_info = alerts_api.snmpInterfaceStatusChangeType(snmp_host, snmp_interface["index"], snmp_interface["name"], snmp_interface["status"]) - - interface.select(getSystemInterfaceId()) - return(alerts_api.store(entity_info, type_info)) -end - -function notify_snmp_device_interface_duplexstatus_change(snmp_host, snmp_interface) - local entity_info = alerts_api.snmpInterfaceEntity(snmp_host, snmp_interface["index"]) - local type_info = alerts_api.snmpInterfaceDuplexStatusChangeType(snmp_host, snmp_interface["index"], snmp_interface["name"], snmp_interface["duplexstatus"]) - - interface.select(getSystemInterfaceId()) - return(alerts_api.store(entity_info, type_info)) -end - -function notify_snmp_device_interface_errors(snmp_host, snmp_interface) - local entity_info = alerts_api.snmpInterfaceEntity(snmp_host, snmp_interface["index"]) - local type_info = alerts_api.snmpInterfaceErrorsType(snmp_host, snmp_interface["index"], snmp_interface["name"]) - - interface.select(getSystemInterfaceId()) - return(alerts_api.store(entity_info, type_info)) -end - -function notify_snmp_device_interface_load_threshold_exceeded(snmp_host, snmp_interface, interface_load, in_direction) - local entity_info = alerts_api.snmpInterfaceEntity(snmp_host, snmp_interface["index"]) - local type_info = alerts_api.snmpPortLoadThresholdExceededType(snmp_host, snmp_interface["index"], snmp_interface["name"], - interface_load, in_direction) - - interface.select(getSystemInterfaceId()) - return(alerts_api.store(entity_info, type_info)) -end - function notify_ntopng_start() return(notify_ntopng_status(true)) end diff --git a/scripts/lua/modules/alerts_api.lua b/scripts/lua/modules/alerts_api.lua index 6dde6dedbd..dc1716ca41 100644 --- a/scripts/lua/modules/alerts_api.lua +++ b/scripts/lua/modules/alerts_api.lua @@ -763,55 +763,92 @@ end -- ############################################## -function alerts_api.snmpInterfaceStatusChangeType(device, interface, interface_name, status) - return({ - alert_type = alert_consts.alert_types.alert_port_status_change, - alert_severity = alert_consts.alert_severities.info, - alert_type_params = { - device = device, interface = interface, - interface_name = interface_name, status = status, - }, - }) +function alerts_api.snmpInterfaceStatusChangeType(snmp_interface_info, device, interface, interface_name, status) + local snmp_interface_index = snmp_interface_info["snmp_interface"]["index"] + local snmp_interface_name = snmp_interface_info["snmp_interface"]["name"] + local snmp_interface_status = snmp_interface_info["if_status"]["status"] + local snmp_device_ip = snmp_interface_info["snmp_device_ip"] + + local res = { + alert_type = alert_consts.alert_types.alert_port_status_change, + alert_severity = alert_consts.alert_severities.info, + alert_type_params = { + device = snmp_device_ip, + interface = snmp_interface_index, + interface_name = snmp_interface_name, + status = snmp_interface_status, + }, + } + + return res end -- ############################################## -function alerts_api.snmpInterfaceDuplexStatusChangeType(device, interface, interface_name, status) - return({ - alert_type = alert_consts.alert_types.alert_port_duplexstatus_change, - alert_severity = alert_consts.alert_severities.warning, - alert_type_params = { - device = device, interface = interface, - interface_name = interface_name, status = status, - }, - }) +function alerts_api.snmpInterfaceDuplexStatusChangeType(snmp_interface_info) + local snmp_interface_index = snmp_interface_info["snmp_interface"]["index"] + local snmp_interface_name = snmp_interface_info["snmp_interface"]["name"] + local snmp_interface_duplexstatus = snmp_interface_info["if_status"]["duplexstatus"] + local snmp_device_ip = snmp_interface_info["snmp_device_ip"] + + local res = { + alert_type = alert_consts.alert_types.alert_port_duplexstatus_change, + alert_severity = alert_consts.alert_severities.warning, + alert_type_params = { + device = snmp_device_ip, + interface = snmp_interface_index, + interface_name = snmp_interface_name, + status = snmp_interface_duplexstatus, + }, + } + + return res end -- ############################################## -function alerts_api.snmpInterfaceErrorsType(device, interface, interface_name) - return({ - alert_type = alert_consts.alert_types.alert_port_errors, - alert_severity = alert_consts.alert_severities.info, - alert_type_params = { - device = device, interface = interface, - interface_name = interface_name, - }, - }) +function alerts_api.snmpInterfaceErrorsType(snmp_interface_info) + local snmp_interface_index = snmp_interface_info["snmp_interface"]["index"] + local snmp_interface_name = snmp_interface_info["snmp_interface"]["name"] + local snmp_device_ip = snmp_interface_info["snmp_device_ip"] + + local res = { + alert_type = alert_consts.alert_types.alert_port_errors, + alert_severity = alert_consts.alert_severities.info, + alert_type_params = { + device = snmp_device_ip, + interface = snmp_interface_index, + interface_name = snmp_interface_name, + }, + } + + return res end -- ############################################## -function alerts_api.snmpPortLoadThresholdExceededType(device, interface, interface_name, interface_load, in_direction) - return({ - alert_type = alert_consts.alert_types.alert_port_load_threshold_exceeded, - alert_severity = alert_consts.alert_severities.warning, - alert_type_params = { - device = device, interface = interface, - interface_name = interface_name, - interface_load = interface_load, in_direction = in_direction, - }, - }) +function alerts_api.snmpPortLoadThresholdExceededType(snmp_interface_info) + local snmp_interface_index = snmp_interface_info["snmp_interface"]["index"] + local snmp_interface_name = snmp_interface_info["snmp_interface"]["name"] + local snmp_device_ip = snmp_interface_info["snmp_device_ip"] + local in_port_load = snmp_interface_info["in_port_load"] + local out_port_load = snmp_interface_info["out_port_load"] + local load_threshold = snmp_interface_info["load_threshold"] + + local res = { + alert_type = alert_consts.alert_types.alert_port_load_threshold_exceeded, + alert_severity = alert_consts.alert_severities.warning, + alert_type_params = { + device = snmp_device_ip, + interface = snmp_interface_index, + interface_name = snmp_interface_name, + in_load = in_port_load, + out_load = out_port_load, + load_threshold = load_threshold, + }, + } + + return res end -- ############################################## @@ -939,6 +976,21 @@ end -- ############################################## +-- TODO: comment +function alerts_api.snmp_device_interface_check_function(params) + local check_res = params.user_script.snmp_device_interface_check(params.granularity, params.entity_info) + + if check_res then + local type_builder = params.user_script.type_builder + + local check_type = type_builder(params.entity_info) + + return alerts_api.store(params.alert_entity, check_type) + end +end + +-- ############################################## + -- An alert check function which performs threshold checks of a value -- against a configured threshold and generates a threshold_cross alert -- if the value is above the threshold. diff --git a/scripts/lua/modules/user_scripts.lua b/scripts/lua/modules/user_scripts.lua index 150225492e..a344033ca8 100644 --- a/scripts/lua/modules/user_scripts.lua +++ b/scripts/lua/modules/user_scripts.lua @@ -38,6 +38,9 @@ user_scripts.script_types = { }, traffic_element = { parent_dir = "interface", hooks = {"min", "5mins", "hour", "day"}, + }, snmp_device = { + parent_dir = "system", + hooks = {"snmpDeviceInterface"}, }, syslog = { parent_dir = "syslog", hooks = {"handleEvent"}, @@ -70,7 +73,7 @@ local benchmarks = {} function user_scripts.getSubdirectoryPath(script_type, subdir, is_pro) local prefix = ternary(is_pro, PRO_CALLBACKS_DIR, CALLBACKS_DIR) local path - + if not isEmptyString(subdir) and subdir ~= "." then path = string.format("%s/%s/%s", prefix, script_type.parent_dir, subdir) else @@ -465,6 +468,7 @@ function user_scripts.load(script_type, ifid, subdir, hook_filter, ignore_disabl elseif(rv.hooks[hook] == nil) then traceError(TRACE_WARNING, TRACE_CONSOLE, string.format("Unknown hook '%s' in module '%s'", hook, user_script.key)) else + if do_benchmark then rv.hooks[hook][user_script.key] = benchmark_init(subdir, user_script.key, hook, hook_fn) else diff --git a/scripts/lua/test_alerts.lua b/scripts/lua/test_alerts.lua index 31d7994a12..190d4f4d2e 100644 --- a/scripts/lua/test_alerts.lua +++ b/scripts/lua/test_alerts.lua @@ -26,5 +26,10 @@ interface.checkNetworksAlertsMin() -- checks the current interface alerts interface.checkInterfaceAlertsMin() +--require "snmp_utils" +--run_5min_snmp_caching(600) +--dofile(dirs.installdir .. "/pro/scripts/callbacks/system/5min.lua") +--ntop.checkSNMPDeviceAlerts5Min() + dofile(dirs.installdir .. "/scripts/lua/inc/footer.lua") diff --git a/src/AlertCheckLuaEngine.cpp b/src/AlertCheckLuaEngine.cpp index 9655fa75d3..746d2b9148 100644 --- a/src/AlertCheckLuaEngine.cpp +++ b/src/AlertCheckLuaEngine.cpp @@ -44,6 +44,9 @@ AlertCheckLuaEngine::AlertCheckLuaEngine(AlertEntity alert_entity, ScriptPeriodi case alert_entity_flow: lua_file = "flow.lua"; break; + case alert_entity_snmp_device: + lua_file = "snmp_device.lua"; + break; default: /* Example: lua_file = "generic.lua" to handle a generic entity */ break; @@ -51,8 +54,9 @@ AlertCheckLuaEngine::AlertCheckLuaEngine(AlertEntity alert_entity, ScriptPeriodi if(lua_file) { snprintf(script_path, sizeof(script_path), - "%s/callbacks/interface/%s", + "%s/callbacks/%s/%s", ntop->getPrefs()->get_scripts_dir(), + iface ? "interface" : "system", lua_file); ntop->fixPath(script_path); diff --git a/src/LuaEngine.cpp b/src/LuaEngine.cpp index a0b1206013..027d663ba5 100644 --- a/src/LuaEngine.cpp +++ b/src/LuaEngine.cpp @@ -291,7 +291,7 @@ static int ntop_set_active_interface_id(lua_State* vm) { ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__); if(ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK) return(CONST_LUA_ERROR); - id = (u_int32_t)lua_tonumber(vm, 1); + id = lua_tonumber(vm, 1); iface = ntop->getNetworkInterface(vm, id); @@ -2569,6 +2569,17 @@ static int ntop_check_interface_alerts_day(lua_State* vm) { return(ntop_check_i /* ****************************************** */ +static int ntop_check_snmp_device_alerts(lua_State* vm, ScriptPeriodicity p) { + ntop->checkSNMPDeviceAlerts(p); + + lua_pushnil(vm); + return(CONST_LUA_OK); +} + +static int ntop_check_snmp_device_alerts_5min(lua_State* vm) { return(ntop_check_snmp_device_alerts(vm, five_minute_script)); } + +/* ****************************************** */ + static int ntop_temporary_disable_alerts(lua_State* vm) { bool to_disable; if(!ntop->isUserAdministrator(vm)) return(CONST_LUA_ERROR); @@ -11321,6 +11332,9 @@ static const luaL_Reg ntop_reg[] = { { "refreshDeviceProtocolsPoliciesConf", ntop_refresh_device_protocols_policies_pref }, #endif + /* Alerts */ + { "checkSNMPDeviceAlerts5Min", ntop_check_snmp_device_alerts_5min }, + { NULL, NULL} }; diff --git a/src/Ntop.cpp b/src/Ntop.cpp index 4acb850b6d..36a0206957 100644 --- a/src/Ntop.cpp +++ b/src/Ntop.cpp @@ -818,6 +818,17 @@ void Ntop::setCustomnDPIProtos(char *path) { } } +/* *************************************** */ + +void Ntop::checkSNMPDeviceAlerts(ScriptPeriodicity p) { + AlertCheckLuaEngine acle(alert_entity_snmp_device, p, NULL); + lua_State *L = acle.getState(); + + lua_getglobal(L, ALERT_ENTITY_CALLBACK_CHECK_ALERTS); /* Called function */ + lua_pushstring(L, acle.getGranularity()); /* push 1st argument */ + acle.pcall(1 /* num args */, 0); +} + /* ******************************************* */ void Ntop::lua_periodic_activities_stats(NetworkInterface *iface, lua_State* vm) {