uSNMP(“micro-SNMP”)是用于开发 SNMPv1 代理和管理器的小型便携式“C”库。Arduino IDE、Windows 和 *nix 的端口包含在源代码中,并已在 Arduino 兼容 (AVR ATmega328p) 和 Arduino Mega 与 Ethernet Shield、NodeMCU v0.9 (Expressif ESP8266)、Windows(使用 Embarcadero BCC32C C++ 编译)上进行了测试编译器)和 Cygwin(使用 gcc)。
在带有 Ethernet Shield 的 Arduino ATmega328p 上,一个实现mib-2::system
表格的 uSNMP 代理,三个极简表格,包括 2 个数字输入(状态切换时发送陷阱)、2 个数字输出和 1 个模拟输入,大约 20kB,包括 SPI ,以太网,UDP,DNS例程。它支持Get、GetNext、Set操作,并在数字输入切换时发送Trap 。2kB SRAM 限制了 MIB 条目的数量和网络数据包的大小(从而限制了请求和响应的长度)。通过放弃该mib-2::system
表,可以将更多的数字和模拟 I/O 引脚添加到相应的表中。在 Arduino Mega 或 ESP8266 上,可以支持更大的缓冲区和更多的 I/O 引脚,因为 SRAM 更大。
该库包括按字典顺序存储和遍历 MIB 树的函数;支持回调函数获取和设置 MIB 叶节点的值,发出 SNMPv1 Get、GetNext、Set请求;构建和处理响应;创建和解析一个 varbind 列表,发送一个Trap并处理 Endianness。
SNMP(简单网络管理协议)是 IT 设备中的事实标准,并在工业和建筑环境领域得到很好的支持:网络设备、服务器和存储、UPS、整流器、远程保护或保护信号设备、RTU、远程 I/ O 等等。它的管理信息库 (MIB) 概念,在 ASN.1 符号的文本文件中定义,是它的超能力。MIB 文件的工作方式类似于数据字典或设备描述语言。它们可以轻松地将新设备载入基于 SNMP 的管理软件,其中有许多包括开源软件,具有地理和拓扑地图覆盖、仪表板、图表、事件日志、事件操作过滤器、故障单等功能。
此设置非常适合物联网应用程序或资产管理,其中有许多相同的站点和设备,但点数很少。相比之下,SCADA/HMI 软件适用于具有多点的单站点,例如过程工厂或建筑物,并具有高度可视化的特征,例如 3D 和动画。
SNMP 协议,尽管它的名字,实际上并不容易实现,也不适合小型处理器,即使对于 SNMPv1 也是如此。SNMPv1 与 v2/v3 相比,您失去了什么?主要针对批量数据查询和安全特性的操作。但是考虑一下:设备的 MIB 仍然可以通过 SNMPv1 操作完全遍历。大多数(如果不是全部)工业协议,包括 Modbus、BACnet 和 Profinet 等占主导地位的协议,都没有内置或安全功能较弱。这不是轻视安全,而是在情况允许的情况下提倡务实。
uSNMP 库扩展了 M. Tim Jones (Charles River Media, 2002. ISBN 1-58450-247-9) 所著的“嵌入式系统的 TCP/IP 应用层协议”一书的第 8 章中介绍的嵌入式 SNMP 服务器,他非常雄辩地写了
“...... SNMP 消息生成的问题是......转发(未知)TLV 长度......为这个问题选择的解决方案是使用预测解析器解析 SNMP 请求并构建响应......我们通过 SNMP PDU 进行预测性解析,当我们到达最终 TLV 时,我们通过函数调用链返回并根据需要更新 TLV 的长度值。”
代理和命令行实用程序的代码示例可用作开发 SNMPv1 代理、发出 SNMPv1 请求和处理响应以及发送陷阱的模板。用于 Windows 和 *nix的示例 uSNMP 代理程序 usnmpd.c从文件中读取 OID 和值对,并且可以用作 SNMPv1 网关,方法是让轮询程序格式化并将其接收到的数据写入此文件。另一个代理示例usnmpd.ino将 Arduino 板转换为具有数字和模拟 I/O 的支持 SNMP 的控制器。MIB 文件位于mibs目录中。ARDUINO.MIB文件用于Arduino 软件 (IDE) 管理板,私有企业编号 (PEN) 是Armadino 的 38644。
让我们更深入地研究一下usnmpd.ino 。对于 NodeMCU 等第 3 方硬件包,首先需要在 Arduino IDE 中添加其 Boards Manager JSON 文件的 URL。URL 指向 Arduino IDE 用来构建可用已安装板的列表的 JSON 索引文件。这可以通过File...Preferences和 NodeMCU 等 ESP8266 板完成:
usnmpd.ino的前几行设置了网络连接(以太网或 WiFi)、IP 地址和代理配置。
// Agent's IP configuration. Retain these global variable names.
IPAddress hostIpAddr( 192, 168, 1, 177 ),
dnsServer( 192, 168, 1, 1 ),
hostGateway( 192, 168, 1, 1 ),
hostNetmask( 255, 255, 255, 0 );
#ifdef ARDUINO_ETHERNET
unsigned char hostMacAddr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
#else // assume ARDUINO_WIFI
char staSSID[] = "Wifi_SSID";
char staPSK[] = "Wifi_Password";
#endif
// SNMP agent configuration.
#define ENTERPRISE_OID "P.38644.30" // used as sysObjectID and in trap
#define RO_COMMUNITY "public"
#define RW_COMMUNITY "private"
#define TRAP_DST_ADDR "192.168.1.170"
uSNMP 为对象 ID 定义了三个前缀,每个有效的 OID 都需要以这些前缀开头:
B denotes Mgmt-Mib2 - 1.3.6.1.2.1
E denotes Experimental - 1.3.6.1.3
P denotes Private-Enterprises - 1.3.6.1.4.1
因此,sysDescr.0 (1.3.6.1.2.1.1.1.0) 将被编码为“B.1.1.0”,“1.3.6.1.4.1.38644.30”的企业 OID 将被编码为“P.38644.30”
setup() 初始化板和代理“引擎”,包括构建 MIB 树和发送冷启动陷阱。引脚 D2 到 D5 设计为数字输入,D6 到 D8 是数字输出,A0 和 A1 是模拟输入,具体取决于目标微控制器上可用的 SRAM 数量。包含 mib-2::system 表后,带有 ATmega328p 的 Arduino UNO 可以具有 D2、D3、D6、D7 和 A0,而 Arduino Mega 可能会超出 D5、D8 和 A1(如果愿意的话)。否则,省略系统表将释放 UNO 上的空间以容纳更多引脚。
initSnmpAgent(SNMP_PORT, ENTERPRISE_OID, RO_COMMUNITY, RW_COMMUNITY);
initMibTree();
trapBuild(&request, enterpriseOID, hostIpAddr, COLD_START, 0, NULL); // cold start trap
trapSend(&request, trapDstAddr, TRAP_DST_PORT, roCommunity);
MIB 树是用函数构建的miblistadd()
,即按照字典顺序将 MIB 离开节点嫁接到它上面。如果需要,随后设置节点的值,并附加回调函数以响应 SNMP Get 和 Set 操作。在下面的摘录中,sysDescr
分配了一个已经包含系统描述的字符串。在用 BER(基本编码规则)编码后用sysObjectID
初始化。设置了回调以在请求获取操作时填写系统正常运行时间。EnterpriseOID
sysUpTime
get_uptime()
/* System MIB */
// sysDescr Entry
thismib = miblistadd(mibTree, "B.1.1.0", OCTET_STRING, RD_ONLY,
sysDescr, strlen(sysDescr));
// sysObjectID Entry
thismib = miblistadd(mibTree, "B.1.2.0", OBJECT_IDENTIFIER, RD_ONLY,
entOIDBer, 0); // set length to 0 first
i = str2ber(enterpriseOID, entOIDBer);
mibsetvalue(thismib, (void *) entOIDBer, (int) i); // proper length set
// sysUptime Entry
thismib = miblistadd(mibTree, "B.1.3.0", TIMETICKS, RD_ONLY, NULL, 0);
i = 0; mibsetvalue(thismib, &i, 0);
mibsetcallback(thismib, get_uptime, NULL);
数字和模拟 I/O 引脚显示在 SNMP 表中。为了节省内存,这些表是极简的,仅包含索引和引脚值。需要回调函数,以便在响应 Get 或 Set 请求时及时检索值。因此,例如,对于数字输出 D6,
// Digital output #6 index
thismib = miblistadd(mibTree, "P.38644.30.2.1.1.6", INTEGER, RD_ONLY, NULL, 0);
i = 6; mibsetvalue(thismib, &i, 0);
// The value of Digital #6
thismib = miblistadd(mibTree, "P.38644.30.2.1.2.6", INTEGER, RD_WR, NULL, 0);
i = 0; mibsetvalue(thismib, &i, 0);
mibsetcallback(thismib, get_dio, set_dio);
代理被设计为在检测到数字输入中的状态变化时发送陷阱。由于 uSNMP 代理不可重入,因此只能在主循环中构建和发送陷阱。
if ( x & 0x01 ) {
vblistReset(&response); dInIndex[17]='0'+y; // use response buffer to build trap
if ( lastDIN & 0x01 ) { // input pin y was 1
i = 0; // it is thus 0 now
vblistAdd(&response, dInIndex, INTEGER, &i, 0);
trapBuild(&request, enterpriseOID, hostIpAddr, ENTERPRISE_SPECIFIC, 1, &response);
}
else {
i = 1;
vblistAdd(&response, dInIndex, INTEGER, &i, 0);
trapBuild(&request, enterpriseOID, hostIpAddr, ENTERPRISE_SPECIFIC, 2, &response);
}
trapSend(&request, trapDstAddr, TRAP_DST_PORT, rwCommunity);
}
同样,如果代理在处理 SNMP 请求时遇到不匹配的社区字符串,它会发送一个身份验证失败陷阱。
if ( processSNMP() == COMM_STR_MISMATCH ) {
trapBuild(&request, enterpriseOID, hostIpAddr, AUTHENTICATE_FAIL, 0, NULL);
trapSend(&request, trapDstAddr, TRAP_DST_PORT, rwCommunity);
}
仅此而已。uSNMP 库具有发出 SNMP 请求和处理响应的功能;并包括用于测试 usnmpd.imo 代理的命令行示例,例如 usnmpget 和 usnmpset。另一种方法是使用 Net-SNMP 二进制文件。两组测试如下所示:
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !