diff --git a/net/smartsnmpd/Makefile b/net/smartsnmpd/Makefile new file mode 100644 index 0000000000..9be39cbacf --- /dev/null +++ b/net/smartsnmpd/Makefile @@ -0,0 +1,75 @@ +# +# Copyright (C) 2014 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=smartsnmpd +PKG_VERSION:=2014-08-13 +PKG_RELEASE=$(PKG_SOURCE_VERSION) + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/credosemi/smartsnmp.git +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=fb93473d895f058b2d8975d3cfa280ae2a8ae98d +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz +PKG_MIRROR_MD5SUM:= + + +PKG_MAINTAINER:=Xiongfei Guo +PKG_LICENSE:=GPL-2.0 +PKG_LICENSE_FILES:=LICENSE + + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/scons.mk + +define Package/smartsnmpd + SECTION:=net + CATEGORY:=Network + DEPENDS+=+lua +liblua +libubox +libuci-lua +libubus-lua + TITLE:=Smart-SNMP (Agent) + URL:=https://github.com/credosemi/smartsnmp +endef + +define Package/smartsnmpd/description +smartsnmpd is an implementation of SNMP Agent. Its goal is "Easily +writing boring SNMP MIB with Lua". This package add native support +for OpenWrt. Include using ubus and uci to get system info/status. +And, it use libubox/uloop as low level event-driven library. +endef + +SCONS_OPTIONS += --transport=uloop + +define Build/Configure + (cd $(PKG_BUILD_DIR); \ + $(SCONS_VARS) \ + scons \ + prefix=/usr \ + $(SCONS_OPTIONS) \ + ) +endef + +define Package/smartsnmpd/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/smartsnmpd $(1)/usr/sbin/smartsnmpd + + $(INSTALL_DIR) $(1)/usr/lib/lua/smartsnmp + $(INSTALL_BIN) $(PKG_BUILD_DIR)/build/smartsnmp/core.so $(1)/usr/lib/lua/smartsnmp/core.so + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lualib/smartsnmp/*.lua $(1)/usr/lib/lua/smartsnmp/ + + $(INSTALL_DIR) $(1)/usr/lib/lua/smartsnmp/mibs + $(INSTALL_BIN) ./files/mibs/*.lua $(1)/usr/lib/lua/smartsnmp/mibs/ + + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_DATA) ./files/smartsnmpd.conf $(1)/etc/config/smartsnmpd + + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/smartsnmpd.init $(1)/etc/init.d/smartsnmpd +endef + +$(eval $(call BuildPackage,smartsnmpd)) + diff --git a/net/smartsnmpd/files/mibs/dummy.lua b/net/smartsnmpd/files/mibs/dummy.lua new file mode 100644 index 0000000000..e49ca683b1 --- /dev/null +++ b/net/smartsnmpd/files/mibs/dummy.lua @@ -0,0 +1,24 @@ +-- +-- This file is part of SmartSNMP +-- Copyright (C) 2014, Credo Semiconductor Inc. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along +-- with this program; if not, write to the Free Software Foundation, Inc., +-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +-- + +local mib = require "smartsnmp" + +local dummy = {} + +return dummy diff --git a/net/smartsnmpd/files/mibs/interfaces.lua b/net/smartsnmpd/files/mibs/interfaces.lua new file mode 100644 index 0000000000..01cea6aecb --- /dev/null +++ b/net/smartsnmpd/files/mibs/interfaces.lua @@ -0,0 +1,125 @@ +-- +-- This file is part of SmartSNMP +-- Copyright (C) 2014, Credo Semiconductor Inc. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along +-- with this program; if not, write to the Free Software Foundation, Inc., +-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +-- + +local mib = require "smartsnmp" +require "ubus" +require "uloop" + +uloop.init() + +local conn = ubus.connect() +if not conn then + error("Failed to connect to ubusd") +end + +local if_cache = {} +local if_status_cache = {} +local if_index_cache = {} + +local last_load_time = os.time() +local function need_to_reload() + if os.time() - last_load_time >= 3 then + last_load_time = os.time() + return true + else + return false + end +end + +local function load_config() + if need_to_reload() == true then + if_cache = {} + if_status_cache = {} + if_index_cache = {} + + -- if description + for k, v in pairs(conn:call("network.device", "status", {})) do + if_status_cache[k] = {} + end + + for name_ in pairs(if_status_cache) do + for k, v in pairs(conn:call("network.device", "status", { name = name_ })) do + if k == 'mtu' then + if_status_cache[name_].mtu = v + elseif k == 'macaddr' then + if_status_cache[name_].macaddr = v + elseif k == 'up' then + if v == true then + if_status_cache[name_].up = 1 + else + if_status_cache[name_].up = 2 + end + elseif k == 'statistics' then + for item, stat in pairs(v) do + if item == 'rx_bytes' then + if_status_cache[name_].in_octet = stat + elseif item == 'tx_bytes' then + if_status_cache[name_].out_octet = stat + elseif item == 'rx_errors' then + if_status_cache[name_].in_errors = stat + elseif item == 'tx_errors' then + if_status_cache[name_].out_errors = stat + elseif item == 'rx_dropped' then + if_status_cache[name_].in_discards = stat + elseif item == 'tx_dropped' then + if_status_cache[name_].out_discards = stat + end + end + end + end + end + + if_cache['desc'] = {} + for name, status in pairs(if_status_cache) do + table.insert(if_cache['desc'], name) + for k, v in pairs(status) do + if if_cache[k] == nil then if_cache[k] = {} end + table.insert(if_cache[k], v) + end + end + + -- if index + for i in ipairs(if_cache['desc']) do + table.insert(if_index_cache, i) + end + end +end + +mib.module_methods.or_table_reg("1.3.6.1.2.1.2", "The MIB module for managing Interfaces implementations") + +local ifGroup = { + [1] = mib.ConstInt(function () load_config() return #if_index_cache end), + [2] = { + [1] = { + [1] = mib.ConstIndex(function () load_config() return if_index_cache end), + [2] = mib.ConstString(function (i) load_config() return if_cache['desc'][i] end), + [4] = mib.ConstInt(function (i) load_config() return if_cache['mtu'][i] end), + [6] = mib.ConstString(function (i) load_config() return if_cache['macaddr'][i] end), + [8] = mib.ConstInt(function (i) load_config() return if_cache['up'][i] end), + [10] = mib.ConstCount(function (i) load_config() return if_cache['in_octet'][i] end), + [13] = mib.ConstCount(function (i) load_config() return if_cache['in_discards'][i] end), + [14] = mib.ConstCount(function (i) load_config() return if_cache['in_errors'][i] end), + [16] = mib.ConstCount(function (i) load_config() return if_cache['out_octet'][i] end), + [19] = mib.ConstCount(function (i) load_config() return if_cache['out_discards'][i] end), + [20] = mib.ConstCount(function (i) load_config() return if_cache['out_errors'][i] end), + } + } +} + +return ifGroup diff --git a/net/smartsnmpd/files/mibs/system.lua b/net/smartsnmpd/files/mibs/system.lua new file mode 100644 index 0000000000..5b0a4af950 --- /dev/null +++ b/net/smartsnmpd/files/mibs/system.lua @@ -0,0 +1,176 @@ +-- +-- This file is part of SmartSNMP +-- Copyright (C) 2014, Credo Semiconductor Inc. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along +-- with this program; if not, write to the Free Software Foundation, Inc., +-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +-- + +local mib = require "smartsnmp" +local uci = require "uci" + +-- System config +local context = uci.cursor("/etc/config", "/tmp/.uci") + +-- scalar index +local sysDesc = 1 +local sysObjectID = 2 +local sysUpTime = 3 +local sysContact = 4 +local sysName = 5 +local sysLocation = 6 +local sysServices = 7 +local sysORLastChange = 8 + +-- table index +local sysORTable = 9 + +-- entry index +local sysOREntry = 1 + +-- list index +local sysORIndex = 1 +local sysORID = 2 +local sysORDesc = 3 +local sysORUpTime = 4 + +local startup_time = 0 +local or_last_changed_time = 0 + +local function mib_system_startup(time) + startup_time = time + or_last_changed_time = time +end + +mib_system_startup(os.time()) + +local sysGroup = {} +local or_oid_cache = {} +local or_index_cache = {} +local or_table_cache = {} + +local or_table_reg = function (oid, desc) + local row = {} + row['oid'] = {} + for i in string.gmatch(oid, "%d") do + table.insert(row['oid'], tonumber(i)) + end + row['desc'] = desc + row['uptime'] = os.time() + table.insert(or_table_cache, row) + + or_last_changed_time = os.time() + + or_oid_cache[oid] = #or_table_cache + + or_index_cache = {} + for i in ipairs(or_table_cache) do + table.insert(or_index_cache, i) + end +end + +local or_table_unreg = function (oid) + local or_idx = or_oid_cache[oid] + + if or_table_cache[or_idx] ~= nil then + table.remove(or_table_cache, or_idx) + or_last_changed_time = os.time() + + or_index_cache = {} + for i in ipairs(or_table_cache) do + table.insert(or_index_cache, i) + end + end +end + +local last_load_time = os.time() +local function need_to_reload() + if os.difftime(os.time(), last_load_time) < 3 then + return false + else + last_load_time = os.time() + return true + end +end + +local function load_config() + if need_to_reload() == true then + context:load("smartsnmpd") + end +end + +context:load("smartsnmpd") + +local sysMethods = { + ["or_table_reg"] = or_table_reg, + ["or_table_unreg"] = or_table_unreg +} +mib.module_method_register(sysMethods) + +sysGroup = { + rocommunity = 'public', + [sysDesc] = mib.ConstString(function () load_config() return mib.sh_call("uname -a") end), + [sysObjectID] = mib.ConstOid(function () + load_config() + local oid + local objectid + context:foreach("smartsnmpd", "smartsnmpd", function (s) + objectid = s.objectid + end) + if objectid ~= nil then + oid = {} + for i in string.gmatch(objectid, "%d+") do + table.insert(oid, tonumber(i)) + end + end + return oid + end), + [sysUpTime] = mib.ConstTimeticks(function () load_config() return os.difftime(os.time(), startup_time) * 100 end), + [sysContact] = mib.ConstString(function () + load_config() + local contact + context:foreach("smartsnmpd", "smartsnmpd", function (s) + contact = s.contact + end) + return contact + end), + [sysName] = mib.ConstString(function () load_config() return mib.sh_call("uname -n") end), + [sysLocation] = mib.ConstString(function () + load_config() + local location + context:foreach("smartsnmpd", "smartsnmpd", function (s) + location = s.location + end) + return location + end), + [sysServices] = mib.ConstInt(function () + load_config() + local services + context:foreach("smartsnmpd", "smartsnmpd", function (s) + services = tonumber(s.services) + end) + return services + end), + [sysORLastChange] = mib.ConstTimeticks(function () load_config() return os.difftime(os.time(), or_last_changed_time) * 100 end), + [sysORTable] = { + [sysOREntry] = { + [sysORIndex] = mib.UnaIndex(function () load_config() return or_index_cache end), + [sysORID] = mib.ConstOid(function (i) load_config() return or_table_cache[i].oid end), + [sysORDesc] = mib.ConstString(function (i) load_config() return or_table_cache[i].desc end), + [sysORUpTime] = mib.ConstTimeticks(function (i) load_config() return os.difftime(os.time(), or_table_cache[i].uptime) * 100 end), + } + } +} + +return sysGroup diff --git a/net/smartsnmpd/files/smartsnmpd.conf b/net/smartsnmpd/files/smartsnmpd.conf new file mode 100644 index 0000000000..aace5a6af6 --- /dev/null +++ b/net/smartsnmpd/files/smartsnmpd.conf @@ -0,0 +1,21 @@ +config smartsnmpd + option port '161' + option ro_community 'public' + option rw_community 'private' + option mib_module_path 'mibs' + option objectid '1.2.3.4' + option contact 'Me ' + option location 'Shanghai' + option services '72' + +config smartsnmpd_module + option oid "1.3.6.1.2.1.1" + option module 'system' + +config smartsnmpd_module + option oid "1.3.6.1.2.1.2" + option module 'interfaces' + +config smartsnmpd_module + option oid "1.3.6.1.1" + option module 'dummy' diff --git a/net/smartsnmpd/files/smartsnmpd.init b/net/smartsnmpd/files/smartsnmpd.init new file mode 100755 index 0000000000..dbe3af8586 --- /dev/null +++ b/net/smartsnmpd/files/smartsnmpd.init @@ -0,0 +1,47 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2014 OpenWrt.org + +START=97 + +USE_PROCD=1 +PROG=/usr/sbin/smartsnmpd +CONFIGFILE=/etc/smartsnmpd.conf + +smartsnmpd_mib_module() { + local cfg="$1" + config_get OID "$cfg" oid + config_get MODULE "$cfg" module + echo " ['$OID'] = '$MODULE'," >> $CONFIGFILE +} + +start_service() { + include /lib/functions + + config_load smartsnmpd + + procd_open_instance + procd_set_param command $PROG -c $CONFIGFILE + procd_set_param file $CONFIGFILE + procd_set_param respawn + procd_close_instance + + # before we can call xappend + mkdir -p $(dirname $CONFIGFILE) + + echo "-- auto-generated config file from /etc/config/smartsnmpd" > $CONFIGFILE + + config_get PORT smartsnmpd port 161 + echo "port = $PORT" >> $CONFIGFILE + + config_get RO_COMMUNITY smartsnmpd ro_community 'public' + config_get RW_COMMUNITY smartsnmpd rw_community 'private' + echo "ro_community = '$RO_COMMUNITY'" >> $CONFIGFILE + echo "rw_community = '$RW_COMMUNITY'" >> $CONFIGFILE + + config_get MIB_MODULE_PATH smartsnmpd mib_module_path '/usr/lib/lua/smartsnmp/mibs/' + echo "mib_module_path = '$MIB_MODULE_PATH'" >> $CONFIGFILE + + echo "mib_modules = {" >> $CONFIGFILE + config_foreach smartsnmpd_mib_module smartsnmpd_module + echo "}" >> $CONFIGFILE +}