监控网络设备流量

监控网路设备的流量貌似目前只能通过 SNMP 协议实现,在 Nagios 的 exchange 里面找了几个脚本,比如 check_cisco.pl 这个,使用的是 MIB 是 ifInOctets/ifOutOctets,这会导致 32 位溢出的问题,并且该脚本最终的结果是 traffic 的总和,而非当前的速度:
$ ./check_cisco.pl -h 192.168.1.10 -c jaseywang-community -i Gi0/1

另外还有个比较火的脚本叫 chekc_snmp.pl 是通过 snmpget 实现,但是选项的表示方式太二了,其他的做的还不错,不过依然不可以统计速度,只能统计总的流量:-(
$ ./check_snmp.pl -w 9 -c 19 -- -c jaseywang-community 192.168.1.10 -v 2c IF-MIB::ifInOctets.10103

然后就没找到“更好”的了,索性还是自己写吧,先了解了下 SNMP 的一些基础,首先安装客户端:
# apt-get autoremove
# apt-get install snmp

可以使用的版本,1、2c、3,目前主流的应该都支持 2c 这个版本,其 community 就相当于 passwd,最新的网络设备上应该都支持 v3 版本:
$ snmpstatus -v 2c -c jaseywang-community 192.168.1.10
$ snmpstatus -v 1 -c jaseywang-community  192.168.1.10
$ snmpstatus -v 3 -c jaseywang-community  192.168.1.10


snmpwalk 会返回我们需要的信息:
$ snmpwalk  -v 2c -c jaseywang-community 192.168.1.10 | head

SNMPv2-MIB::sysObjectID.0 = OID: SNMPv2-SMI::enterprises.9.1.697
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (1241787960) 143 days, 17:24:39.60
SNMPv2-MIB::sysContact.0 = STRING: jaseywang#gmail.com
SNMPv2-MIB::sysName.0 = STRING: jaseywang-community.gmail.com
SNMPv2-MIB::sysLocation.0 = STRING: Beijing

上面的结构类似 key-value 的结构,左边的术语叫:object identifier(OID):
$ snmpwalk  -v 2c -c jaseywang-community 192.168.1.10  SNMPv2-SMI::mib-2.47.1.3.3.1.1.1002.1047
SNMPv2-SMI::mib-2.47.1.3.3.1.1.1002.1047 = INTEGER: 1047

完整的 OID 包含两部分:management information base(MIB),用来将数字表达的 OID map 到文字形式;第二部分是该 MIB 的唯一描述符。可以通过 -Of flag 来显示完整的 OID:
$ snmpwalk  -v 2c -c jaseywang-community 192.168.1.10 -Of DISMAN-EVENT-MIB::sysUpTimeInstance
.iso.org.dod.internet.mgmt.mib-2.system.sysUpTime.sysUpTimeInstance = Timeticks: (1241885547) 143 days, 17:40:55.47
$ snmpget -v 2c -c jaseywang-community  -Of 192.168.1.10 SNMPv2-MIB::sysLocation.0
.iso.org.dod.internet.mgmt.mib-2.system.sysLocation.0 = STRING: Beijing

同样的,还可以通过 -On 来以数字的形式显示:
$ snmpwalk  -v 2c -c jaseywang-community 192.168.1.10 -On DISMAN-EVENT-MIB::sysUpTimeInstance
.1.3.6.1.2.1.1.3.0 = Timeticks: (1241891919) 143 days, 17:41:59.19
$ snmpget -v 2c -c jaseywang-community  -On 192.168.1.10 SNMPv2-MIB::sysLocation.0
.1.3.6.1.2.1.1.6.0 = STRING: Beijing

每一个 OID 都可以使用上面的三种方式表示,short, long, numeric:DISMAN-EVENT-MIB::sysUpTimeInstance, .iso.org.dod.internet.mgmt.mib-2.system.sysUpTime.sysUpTimeInstance, .1.3.6.1.2.1.1.6.0。

可以使用 snmptranslate 进行字母与数字的翻译:
$ snmptranslate  -On DISMAN-EVENT-MIB::sysUpTimeInstance
.1.3.6.1.2.1.1.3.0
$ snmptranslate  -Of DISMAN-EVENT-MIB::sysUpTimeInstance
.iso.org.dod.internet.mgmt.mib-2.system.sysUpTime.sysUpTimeInstance

跟网络流量相关的如下:
$ snmpwalk  -v 2c -c jaseywang-community 192.168.1.10  | grep IF-MIB | tee traffic
IF-MIB::ifDescr.1 = STRING: Vlan1
IF-MIB::ifDescr.2 = STRING: Vlan2
IF-MIB::ifDescr.10101 = STRING: GigabitEthernet0/1
..
IF-MIB::ifInOctets.1 = Counter32: 0
IF-MIB::ifInOctets.2 = Counter32: 1297121156
IF-MIB::ifInOctets.10101 = Counter32: 4268941992

IF-MIB::ifOutOctets.1 = Counter32: 832
IF-MIB::ifOutOctets.2 = Counter32: 762275067
IF-MIB::ifOutOctets.10101 = Counter32: 3145772328
IF-MIB::ifOutOctets.10102 = Counter32: 0

可以进行“模糊”查询:
$ snmpwalk -v 2c -c jaseywang-community 192.168.1.10 IF-MIB::ifInOctets
IF-MIB::ifInOctets.1 = Counter32: 0
IF-MIB::ifInOctets.2 = Counter32: 1297748400
IF-MIB::ifInOctets.10101 = Counter32: 1491097985
IF-MIB::ifInOctets.10102 = Counter32: 0

上面显示的 ifInOctets 以及 ifOutOctets 均为 32 bin的,会产生溢出,因此,最好选择 ifHCOutOctets, ifHCInOctets 这两个 OID:
$ snmpwalk -v 2c -c jaseywang-community 192.168.1.10 IF-MIB::ifHCInOctets
IF-MIB::ifHCInOctets.1 = Counter64: 0
IF-MIB::ifHCInOctets.2 = Counter64: 1341805678
IF-MIB::ifHCInOctets.10101 = Counter64: 385875906022080
IF-MIB::ifHCInOctets.10102 = Counter64: 0
IF-MIB::ifHCInOctets.10103 = Counter64: 83733707726527

由上面 tee 到的文件可以看到有如下几个 OID 是跟流量/网络紧密相关的:
ifIndex, ifDescr, ifType, ifMtu, ifPhysAddress, ifOperStatus
ifInOctets, ifInUcastPkts, ifInNUcastPkts, ifInDiscards, ifInErrors, ifInUnknownProtos, 与之对应的还有 out 值

部署有 SNMP 的机器跟中央节点有两种通信方式,一是中心节点主动获取 snmp 的机器,也就是 query,第二种是由 snmp 机器主动发送信息给中心节点,在 snmp 到达某个条件时,这个称为 traps

实际脚本很简单,获取一个 delt 时间段内的某个接口的流量,相减除以 delt 就可以得到一个近似速度,最后符合 Nagios 的规范,有 warning, critical 就可以了。