--- /dev/null
+#
+# 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 <xfguo@credosemi.com>
+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))
+
--- /dev/null
+--
+-- 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
--- /dev/null
+--
+-- 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
--- /dev/null
+--
+-- 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
--- /dev/null
+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 <me@example.org>'
+ 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'
--- /dev/null
+#!/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
+}