diff --git a/src/mod/event_handlers/mod_snmp/FREESWITCH-MIB b/src/mod/event_handlers/mod_snmp/FREESWITCH-MIB new file mode 100644 index 0000000000..9584c8bac3 --- /dev/null +++ b/src/mod/event_handlers/mod_snmp/FREESWITCH-MIB @@ -0,0 +1,110 @@ +FREESWITCH-MIB DEFINITIONS ::= BEGIN + +IMPORTS + OBJECT-TYPE, MODULE-IDENTITY, + Integer32, Gauge32, Counter32, Counter64, TimeTicks, + enterprises, + FROM SNMPv2-SMI + + DisplayString + FROM SNMPv2-TC +; + + +freeswitch MODULE-IDENTITY + LAST-UPDATED "201101170000Z" + ORGANIZATION "www.freeswitch.org" + CONTACT-INFO + "Primary contact: Anthony Minessale II + Email: anthm@freeswitch.org" + DESCRIPTION + "This file defines the private FreeSWITCH SNMP MIB extensions." + REVISION "201101170000Z" + DESCRIPTION + "First draft by daniel.swarbrick@seventhsignal.de" + ::= { enterprises 27880 } + + +core OBJECT IDENTIFIER ::= { freeswitch 1 } +mod-sofia OBJECT IDENTIFIER ::= { freeswitch 1001 } +mod-skinny OBJECT IDENTIFIER ::= { freeswitch 1002 } + + +identity OBJECT IDENTIFIER ::= { core 1 } + +versionString OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "FreeSWITCH version as a string" + ::= { identity 1 } + +uuid OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "FreeSWITCH core UUID" + ::= { identity 2 } + + +systemStats OBJECT IDENTIFIER ::= { core 2 } + +uptime OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "FreeSWITCH process uptime in hundredths of seconds" + ::= { systemStats 1 } + +sessionsSinceStartup OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of sessions since FreeSWITCH process was started" + ::= { systemStats 2 } + +currentSessions OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Currently active sessions" + ::= { systemStats 3 } + +maxSessions OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Maximum permissible active sessions" + ::= { systemStats 4 } + +currentCalls OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Currently active calls" + ::= { systemStats 5 } + +sessionsPerSecond OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current sessions per second" + ::= { systemStats 6 } + +maxSessionsPerSecond OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Maximum permissible sessions per second" + ::= { systemStats 7 } + +END diff --git a/src/mod/event_handlers/mod_snmp/Makefile b/src/mod/event_handlers/mod_snmp/Makefile new file mode 100644 index 0000000000..1d8827daf1 --- /dev/null +++ b/src/mod/event_handlers/mod_snmp/Makefile @@ -0,0 +1,7 @@ +include ../../../../build/modmake.rules + +LOCAL_CFLAGS=-I `net-snmp-config --cflags` +LOCAL_LDFLAGS=`net-snmp-config --agent-libs` +LOCAL_OBJS=subagent.o + +local_depend: $(LOCAL_OBJS) diff --git a/src/mod/event_handlers/mod_snmp/mod_snmp.c b/src/mod/event_handlers/mod_snmp/mod_snmp.c new file mode 100644 index 0000000000..040e82b602 --- /dev/null +++ b/src/mod/event_handlers/mod_snmp/mod_snmp.c @@ -0,0 +1,138 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2011, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Swarbrick + * Stefan Knoblich + * + * mod_snmp.c -- SNMP AgentX Subagent Module + * + */ +#include + +#include +#include +#include + +#include "subagent.h" + +static struct { + switch_memory_pool_t *pool; + int shutdown; +} globals; + +SWITCH_MODULE_LOAD_FUNCTION(mod_snmp_load); +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_snmp_shutdown); +SWITCH_MODULE_RUNTIME_FUNCTION(mod_snmp_runtime); +SWITCH_MODULE_DEFINITION(mod_snmp, mod_snmp_load, mod_snmp_shutdown, mod_snmp_runtime); + + +static int snmp_callback_log(int major, int minor, void *serverarg, void *clientarg) +{ + struct snmp_log_message *slm = (struct snmp_log_message *) serverarg; + switch_log_printf(SWITCH_CHANNEL_LOG, slm->priority, "%s", slm->msg); + return SNMP_ERR_NOERROR; +} + + +static switch_state_handler_table_t state_handlers = { + /*.on_init */ NULL, + /*.on_routing */ NULL, + /*.on_execute */ NULL, + /*.on_hangup */ NULL, + /*.on_exchange_media */ NULL, + /*.on_soft_execute */ NULL, + /*.on_consume_media */ NULL, + /*.on_hibernate */ NULL, + /*.on_reset */ NULL, + /*.on_park */ NULL, + /*.on_reporting */ NULL +}; + + +static switch_status_t load_config(switch_memory_pool_t *pool) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + + memset(&globals, 0, sizeof(globals)); + globals.pool = pool; + + return status; +} + + +SWITCH_MODULE_LOAD_FUNCTION(mod_snmp_load) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + + load_config(pool); + + switch_core_add_state_handler(&state_handlers); + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + /* Register callback function so we get Net-SNMP logging handled by FreeSWITCH */ + snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, snmp_callback_log, NULL); + snmp_enable_calllog(); + + netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1); + netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); + + init_agent("mod_snmp"); + init_subagent(); + init_snmp("mod_snmp"); + + return status; +} + + +SWITCH_MODULE_RUNTIME_FUNCTION(mod_snmp_runtime) +{ + /* block on select() */ + agent_check_and_process(1); + + return SWITCH_STATUS_SUCCESS; +} + + +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_snmp_shutdown) +{ + globals.shutdown = 1; + switch_core_remove_state_handler(&state_handlers); + + snmp_shutdown("mod_snmp"); + + return SWITCH_STATUS_SUCCESS; +} + + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/mod/event_handlers/mod_snmp/subagent.c b/src/mod/event_handlers/mod_snmp/subagent.c new file mode 100644 index 0000000000..8a9f2dac21 --- /dev/null +++ b/src/mod/event_handlers/mod_snmp/subagent.c @@ -0,0 +1,189 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2011, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Swarbrick + * Stefan Knoblich + * + * mod_snmp.c -- SNMP AgentX Subagent Module + * + */ +#include +#include + +#include +#include +#include +#include "subagent.h" + + +static oid identity_oid[] = { 1,3,6,1,4,1,27880,1,1 }; +static oid systemStats_oid[] = { 1,3,6,1,4,1,27880,1,2 }; + +/* identity sub-IDs - these must match MIB */ +enum { + versionString_oid = 1, + uuid_oid +}; + + +/* systemStats sub-IDs - these must match MIB */ +enum { + uptime_oid = 1, + sessionsSinceStartup_oid, + currentSessions_oid, + maxSessions_oid, + currentCalls_oid, + sessionsPerSecond_oid, + maxSessionsPerSecond_oid +}; + + +void init_subagent(void) +{ + DEBUGMSGTL(("init_nstAgentSubagentObject", "Initializing\n")); + + netsnmp_register_handler(netsnmp_create_handler_registration("identity", handle_identity, identity_oid, OID_LENGTH(identity_oid), HANDLER_CAN_RONLY)); + netsnmp_register_handler(netsnmp_create_handler_registration("systemStats", handle_systemStats, systemStats_oid, OID_LENGTH(systemStats_oid), HANDLER_CAN_RONLY)); +} + + +int handle_identity(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) +{ + static char const version[] = SWITCH_VERSION_FULL; + char uuid[40] = ""; + netsnmp_request_info *request = NULL; + oid subid; + + switch(reqinfo->mode) { + case MODE_GET: + for (request = requests; request; request = request->next) { + subid = request->requestvb->name[OID_LENGTH(systemStats_oid)]; + + switch (subid) { + case versionString_oid: + snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) &version, strlen(version)); + break; + case uuid_oid: + strncpy(uuid, switch_core_get_uuid(), sizeof(uuid)); + snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) &uuid, strlen(uuid)); + break; + default: + snmp_log(LOG_WARNING, "Unregistered OID-suffix requested (%d)\n", (int) subid); + netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT); + } + } + break; + + case MODE_GETNEXT: + snmp_log(LOG_ERR, "MODE_GETNEXT not supported (yet)\n"); + break; + + default: + /* we should never get here, so this is a really bad error */ + snmp_log(LOG_ERR, "Unknown mode (%d) in handle_versionString\n", reqinfo->mode ); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} + + +int handle_systemStats(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) +{ + netsnmp_request_info *request = NULL; + oid subid; + switch_time_t uptime; + uint32_t int_val; + + switch(reqinfo->mode) { + case MODE_GET: + for (request = requests; request; request = request->next) { + subid = request->requestvb->name[OID_LENGTH(systemStats_oid)]; + + switch (subid) { + case uptime_oid: + uptime = switch_core_uptime() / 10000; + snmp_set_var_typed_value(requests->requestvb, ASN_TIMETICKS, (u_char *) &uptime, sizeof(uptime)); + break; + case sessionsSinceStartup_oid: + int_val = switch_core_session_id() - 1; + snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &int_val, sizeof(int_val)); + break; + case currentSessions_oid: + int_val = switch_core_session_count(); + snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val)); + break; + case maxSessions_oid: + switch_core_session_ctl(SCSC_MAX_SESSIONS, &int_val);; + snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val)); + break; + case currentCalls_oid: + /* + * This is zero for now, since there is no convenient way to get total call + * count (not to be confused with session count), without touching the + * database. + */ + int_val = 0; + snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val)); + break; + case sessionsPerSecond_oid: + switch_core_session_ctl(SCSC_LAST_SPS, &int_val); + snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val)); + break; + case maxSessionsPerSecond_oid: + switch_core_session_ctl(SCSC_SPS, &int_val); + snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val)); + break; + default: + snmp_log(LOG_WARNING, "Unregistered OID-suffix requested (%d)\n", (int) subid); + netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT); + } + } + break; + + case MODE_GETNEXT: + snmp_log(LOG_ERR, "MODE_GETNEXT not supported (yet)\n"); + break; + + default: + /* we should never get here, so this is a really bad error */ + snmp_log(LOG_ERR, "Unknown mode (%d) in handle_systemStats\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} + + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/mod/event_handlers/mod_snmp/subagent.h b/src/mod/event_handlers/mod_snmp/subagent.h new file mode 100644 index 0000000000..8a57d8a9f7 --- /dev/null +++ b/src/mod/event_handlers/mod_snmp/subagent.h @@ -0,0 +1,8 @@ +#ifndef subagent_H +#define subagent_H + +void init_subagent(void); +Netsnmp_Node_Handler handle_identity; +Netsnmp_Node_Handler handle_systemStats; + +#endif /* subagent_H */