SNMP base(轉個普及貼)

火星人 @ 2014-03-03 , reply:0
←手機掃碼閱讀

SNMP base(轉個普及貼)

SNMP base(轉個普及貼)

Linux 提供了一些簡單的工具,如 ps, top, free, df, vmstat 等,對於臨時的查看系統資源和狀態很有用,但對於一個大型的網路系統,我需要有長期自動獲取的統計數據,來對伺服器每天、每月、每年的資源和狀態情況有一個整體上的認識,以及對 CPU/MEM/IO/Network trafic 的長期比較以確定性能瓶頸所在,並且能夠長期監控關鍵服務,在出問題的時候自動發送郵件和簡訊等進行通知。
有一些可以在後台長期運行並周期查看系統資源的工具,如 sar,但它通常是針對一個單系統的,在多主機的環境下,其數據的管理就不太方便了;其抓取的二進位數據基本上只能自己使用,而這些數據並不具有直觀性,不太利於分析,同時又缺乏其他工具的支持以使得數據能夠以諸如圖形的方式顯示出來,所以對體系結構的建設來說並不是太好的選擇。
相對來說,SNMP 數據的內容更加全面,而且其基於網路協議的方式使得管理多系統的大環境變得相對簡單,其數據的組織形式也相對較好,它只提供系統當前狀態的數據,而不像 sar 那樣提高全部周期的數據,因此當前狀態的數據可以做得非常詳細,而統計的事情就交給其他工具去完成 -- 這符合 UNIX 的 KISS 原則:寧可要功能單一但非常專業的工具,然後將這些工具組合起來完成更複雜的任務。
通過其他工具的支持,可以取得長期的統計數據(如 Cacti),並將這些數據存儲為更利於操作的形式,例如進行疊加、合併等(如 rrdtool)。
當然,其學習曲線不是那麼平緩,
SNMP(Simple Network Management Protocal, 簡單網路管理協議)在架構體系的監控子系統中將扮演重要角色。大體上,其基本原理是,在每一個被監控的主機或節點上 (如交換機)都運行了一個 agent,用來收集這個節點的所有相關的信息,同時監聽 snmp 的 port,也就是 UDP 161,並從這個埠接收來自監控主機的指令(查詢和設置)。
如果使用 RHEL4 的 net-snmp,那麼被監控主機需要安裝 net-snmp(包含了 snmpd 這個 agent),而監控端需要安裝 net-snmp-utils。如果自行編譯,需要 beecrypt(libbeecrypt)和 elf(libraryelf)的庫。
每一個 agent 維護一個樹形的資料庫,稱為 MID(Management Information Base, 管理信息庫),其每一個節點稱為 Object Identifier(OID),這在使用 net-snmp-utils 的工具時會用到。這些節點就表示了這台主機系統的設備如網卡的介面描述(eth0 等)、物理地址(MAC)、介面類型等,也可能是系統的信息,或者是需要監控的進程等...
net-snmp-utils 的工具集的所有參數不能直接在其 man 手冊中查到,可以查 man snmpcmd ,這個命令並不實際存在,只是說明的所有 utils 命令共同的參數。
SNMP MIBs base && some utils
MID(Management Information Base, 管理信息庫)這個樹形資料庫是按照數字(numeric)來組織的,即每一個節點(OID)都是數字,因此有一個名字到數字的映射關係,例如 system , interfaces 這樣的名字要映射到各個被控端的實際設備節點上,或反之需要知道實際的名字。所有這些映射關係的定義都在 MIB 文件中,即 /usr/share/snmp/mibs (根據實際的安裝情況會有不同)。例如:
  sh$ grep 'system' /usr/share/snmp/mibs/SNMPv2-MIB.txt
  system   OBJECT IDENTIFIER ::= { mib-2 1 }
  ......

snmptranslate 這個命令可以用來查看映射關係:
  sh$ snmptranslate .1.3.6.1.2.1.1.3.0
  SNMPv2-MIB::sysUpTime.0
  sh$ snmptranslate -On SNMPv2-MIB::system.sysUpTime.0
  .1.3.6.1.2.1.1.3.0
可以看到這個 SNMPv2-MIB 其實就是 /usr/share/snmp/mibs/SNMPv2-MIB.txt。
如果要使用自定義的 local MIBs,可以參見: NET-SNMP Tutorial -- Using local MIBs
使用 snmpwalk 可以取得一個樹的結果:
  sh$ snmpwalk -v2c -c public localhost system
  SNMPv2-MIB::sysDescr.0 = STRING: Linux localhost.localdomain 2.6.14.2 #1 SMP Thu Jan 11 15:39:36 EST 2007 i686
  SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
  SNMPv2-MIB::sysUpTime.0 = Timeticks: (687617) 1:54:36.17
  SNMPv2-MIB::sysContact.0 = STRING: zhoupeng@zovatech.com
  SNMPv2-MIB::sysName.0 = STRING: localhost.localdomain
  SNMPv2-MIB::sysLocation.0 = STRING: Unknown (edit /etc/snmp/snmpd.conf)
  SNMPv2-MIB::sysORLastChange.0 = Timeticks: (1) 0:00:00.01
  SNMPv2-MIB::sysORID.1 = OID: IF-MIB::ifMIB
  SNMPv2-MIB::sysORID.2 = OID: SNMPv2-MIB::snmpMIB
  SNMPv2-MIB::sysORID.3 = OID: TCP-MIB::tcpMIB
  SNMPv2-MIB::sysORID.4 = OID: IP-MIB::ip
  SNMPv2-MIB::sysORID.5 = OID: UDP-MIB::udpMIB
  SNMPv2-MIB::sysORID.6 = OID: SNMP-VIEW-BASED-ACM-MIB::vacmBasicGroup
  SNMPv2-MIB::sysORID.7 = OID: SNMP-FRAMEWORK-MIB::snmpFrameworkMIBCompliance
  SNMPv2-MIB::sysORID.8 = OID: SNMP-MPD-MIB::snmpMPDCompliance
  SNMPv2-MIB::sysORID.9 = OID: SNMP-USER-BASED-SM-MIB::usmMIBCompliance
  SNMPv2-MIB::sysORDescr.1 = STRING: The MIB module to describe generic objects for network interface sub-layers
  SNMPv2-MIB::sysORDescr.2 = STRING: The MIB module for SNMPv2 entities
  SNMPv2-MIB::sysORDescr.3 = STRING: The MIB module for managing TCP implementations
  SNMPv2-MIB::sysORDescr.4 = STRING: The MIB module for managing IP and ICMP implementations
  SNMPv2-MIB::sysORDescr.5 = STRING: The MIB module for managing UDP implementations
  SNMPv2-MIB::sysORDescr.6 = STRING: View-based Access Control Model for SNMP.
  SNMPv2-MIB::sysORDescr.7 = STRING: The SNMP Management Architecture MIB.
  SNMPv2-MIB::sysORDescr.8 = STRING: The MIB for Message Processing and Dispatching.
  SNMPv2-MIB::sysORDescr.9 = STRING: The management information definitions for the SNMP User-based Security Model.
  SNMPv2-MIB::sysORUpTime.1 = Timeticks: (0) 0:00:00.00
  SNMPv2-MIB::sysORUpTime.2 = Timeticks: (1) 0:00:00.01
  SNMPv2-MIB::sysORUpTime.3 = Timeticks: (1) 0:00:00.01
  SNMPv2-MIB::sysORUpTime.4 = Timeticks: (1) 0:00:00.01
  SNMPv2-MIB::sysORUpTime.5 = Timeticks: (1) 0:00:00.01
  SNMPv2-MIB::sysORUpTime.6 = Timeticks: (1) 0:00:00.01
  SNMPv2-MIB::sysORUpTime.7 = Timeticks: (1) 0:00:00.01
  SNMPv2-MIB::sysORUpTime.8 = Timeticks: (1) 0:00:00.01
  SNMPv2-MIB::sysORUpTime.9 = Timeticks: (1) 0:00:00.01
  
  sh$ snmpwalk -v2c -c public localhost interfaces
  IF-MIB::interfaces = No Such Object available on this agent at this OID

如果增加 -Of 參數可以得到一個完整的樹形表達。我不太明白這裡的 system 和 interfaces 是如何定義和識別的?因為如果使用 snmpget 這樣就不行:
  sh$ snmpget -v2c -c public localhost system
  SNMPv2-MIB::system = No Such Object available on this agent at this OID
  sh$ snmpget -v2c -c public localhost SNMPv2-MIB::system
  SNMPv2-MIB::system = No Such Object available on this agent at this OID
  sh$ snmpget -v2c -c public localhost SNMPv2-MIB::sysDescr.0
  SNMPv2-MIB::sysDescr.0 = STRING: Linux localhost.localdomain 2.6.14.2 #1 SMP Thu Jan 11 15:39:36 EST 2007 i686

現在我知道 interfaces 的一些 MIB(《Linux Server Hacks, 卷二》),前面用 snmpwalk 得不到結果,那麼現在用 snmpget 呢?
  sh$ snmpget -v2c -c public localhost IF-MIB::ifDescr.1
  IF-MIB::ifDescr.1 = No Such Object available on this agent at this OID

再參考 net-snmp 的 FAQ,使用 snmpgetnext:
  sh$ snmpgetnext -v2c -c public localhost IF-MIB::ifDescr.1
  HOST-RESOURCES-MIB::hrSystemUptime.0 = Timeticks: (70364798) 8 days, 3:27:27.98
  sh$ snmpgetnext -v2c -c public localhost HOST-RESOURCES-MIB::hrSystemUptime.0
  HOST-RESOURCES-MIB::hrSystemUptime.0 = No more variables left in this MIB View (It is past the end of the MIB tree)

根據此 FAQ 上的說明,這樣是會有問題的,因為實際上是使用了別的 MIB 文件,或者得到諸如"end of MIB"的響應,應該要更改配置,那麼如何來做?在《Linux Server Hacks, Volume 2》上,是如下的表示:
  IF-MIB::ifDescr.1 = STRING: lo
  IF-MIB::ifDescr.2 = STRING: eth0
  ...

以上都是由於 SNMP 的 access control 配置引起的,SNMP 的 access control 可以控制對 MIB 樹的某個分支可以由那些 IP 段來讀取和修改等。
SNMP access control(未完)
前面已經了解了 SNMP 及其 MIBs,並且使用了一些工具來查看 MIB 樹。但是問題是,我只能看到 system 這一分支的情況,即:
  snmpwalk -v2c -c public localhost system
而 interfaces 就不行,這樣如何監控網路的流量呢?而使用 snmpget 也得不到需要的 IF-MIB:: 中的信息,使用 snmpgetnext 得到的也不正確。snmpgetnext 應該是得到下一個(NEXT)節點的信息,例如:
  sh$ snmpwalk -v2c -c demo 192.168.0.98 system | head -n 2
  SNMPv2-MIB::sysDescr.0 = STRING: Linux localhost.localdomain 2.6.14.2 #1 SMP Thu Jan 11 15:39:36 EST 2007 i686
  SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
  sh$ snmpget -v2c -c demo 192.168.0.98 SNMPv2-MIB::sysDescr.0
  SNMPv2-MIB::sysDescr.0 = STRING: Linux localhost.localdomain 2.6.14.2 #1 SMP Thu Jan 11 15:39:36 EST 2007 i686
  sh$ snmpgetnext -v2c -c demo 192.168.0.98 SNMPv2-MIB::sysDescr.0
  SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10

這裡 -c demo 是一個 community name,而且這裡也不是使用的 localhost 而是 192.168.0.98 這樣的地址,這是因為更改了 snmpd.conf 的緣故,實際上,如果不更改而使用默認的 snmpd.conf,那麼只能使用 -c public localhost,否則只能得到諸如: "Timeout: No Response from 192.168.0.98."這樣的信息。這些會在下面講到。
根據 net-snmp FAQ "I can see the system group, but nothing else. Why?" 上的說明,無法得到 interfaces 這個子樹的原因是由於 agent 的 access control 的緣故。那麼在 netsnmp FAQ "How do I configure access control?" 和 net-snmp FAQ "I don't understand the new access control stuff - what does it mean?" 這兩個部分說明了如何來配置 agent 的 access control。
我們現在只考慮 SNMPv2,不考慮 SNMPv3。 那麼 access control 要解決的問題就是:我要讓哪些人(who)可以獲取哪些子樹(what)。 與此相關的幾個語句是 com2sec, group, view 和 access。
那麼先來看看 access 語句,它就是定義哪些人可以獲取哪些子樹的語句。其語法為:
  access {group} "" any noauth exact {read-tree} {write-tree} {notify-tree}
這裡 {group} 就是將要用 group 語句來定義的組, {read-tree} {write-tree} {notify-tree} 就是將要用 view 來定義的子樹。 所以 group 就是哪些人,view 就是哪些子樹。
於是用 group 來定義哪些人:
  # com2sec notConfigUser  default       public
  # group   notConfigGroup  v1           notConfigUser
  # group   notConfigGroup  v2c          notConfigUser
  com2sec mynet     192.168.0.0/24  demo
  group   gmynet     v1              mynet
  group   gmynet     v2c             mynet

為了更清楚的說明,這裡我將原來的註釋掉了。v1/v2c 是 serurityModel,就是在 snmpwalk/snmpget 這些命令使用時使用的參數如 -v2c(-v 2c)。所以我們的 group 為 gmynet,它與 mynet 這個名字(security name)是一個映射關係,而為了簡便起見,也可以直接定義 group 為 mynet,而不用繞這麼多圈子:
  group   mynet     v1              mynet
  group   mynet     v2c             mynet

com2sec 即 community to security,實際上定義了一個基於 地址的訪問控制,另外它大概還有一個將 SNMPv2/SNMPv1 的名字映射過來的作用,如上的 demo,這樣在 snmpwalk/snmpget 時使用 -v2c 這樣的參數時可以使用 -c demo。按照上面的方式定義之後,就只能使用上面的 snmpwalk/snmpget -v2c -c demo 192.168.0.98 這樣的形式,而不能再使用 -c public localhost 了,否則就得到 "Timeout: No Response from localhost"這樣的出錯。
然後用 view 來定義可以查看哪些子樹:
  view    interface included       .1.3.6.1.2.1.2
  view    system    included       .1.3.6.1.2.1.1
  view    system    included       .1.3.6.1.2.1.25.1.1
可以利用 snmptranslate 來得到 numeric 樹,
  sh$ snmptranslate -On IF-MIB::interfaces
  .1.3.6.1.2.1.2
  sh$ snmptranslate -On SNMPv2-MIB::system
  .1.3.6.1.2.1.1
也可以直接使用 MIB 定義。
那麼 access 的定義就應該如下:
  access  mynet ""  any  noauth  exact  system  none  none
  access  mynet ""  any  noauth  exact  interface  none  none

這樣,按道理就應該可以得到 interfaces 的值了。記得要使 agent 重新讀取配置文件,在 RHEL4 下面使用 /etc/init.d/snmpd restart 即可。
但實際上卻不行:
  sh$ snmpwalk -v2c -c demo 192.168.0.98 interfaces
  IF-MIB::interfaces = No Such Object available on this agent at this OID
  sh$ snmpget -v2c -c demo 192.168.0.98 IF-MIB::ifDescr.1
  IF-MIB::ifDescr.1 = No Such Object available on this agent at this OID

但是如果使用如下的設置卻可以:
  view    all       included       .1
  access  mynet "" any  noauth  exact  all  none  none
  
  sh$ snmpwalk -v2c -c demo 192.168.0.98 interface
  IF-MIB::ifNumber.0 = INTEGER: 4
  IF-MIB::ifIndex.1 = INTEGER: 1
  IF-MIB::ifIndex.2 = INTEGER: 2
  IF-MIB::ifIndex.3 = INTEGER: 3
  IF-MIB::ifIndex.4 = INTEGER: 4
  IF-MIB::ifDescr.1 = STRING: lo
  IF-MIB::ifDescr.2 = STRING: eth0
  IF-MIB::ifDescr.3 = STRING: eth1
  IF-MIB::ifDescr.4 = STRING: sit0
  IF-MIB::ifType.1 = INTEGER: softwareLoopback(24)
  IF-MIB::ifType.2 = INTEGER: ethernetCsmacd(6)
  IF-MIB::ifType.3 = INTEGER: ethernetCsmacd(6)
  IF-MIB::ifType.4 = INTEGER: tunnel(131)
  IF-MIB::ifMtu.1 = INTEGER: 16436
  IF-MIB::ifMtu.2 = INTEGER: 1500
  IF-MIB::ifMtu.3 = INTEGER: 1500
  IF-MIB::ifMtu.4 = INTEGER: 1480
  IF-MIB::ifSpeed.1 = Gauge32: 10000000
  IF-MIB::ifSpeed.2 = Gauge32: 100000000
  IF-MIB::ifSpeed.3 = Gauge32: 10000000
  IF-MIB::ifSpeed.4 = Gauge32: 0
  IF-MIB::ifPhysAddress.1 = STRING:
  IF-MIB::ifPhysAddress.2 = STRING: 0:2:b3:b0:59:36
  IF-MIB::ifPhysAddress.3 = STRING: 0:2:b3:b0:59:4a
  IF-MIB::ifPhysAddress.4 = STRING: 0:0:0:0:59:4a
  IF-MIB::ifAdminStatus.1 = INTEGER: up(1)
  IF-MIB::ifAdminStatus.2 = INTEGER: up(1)
  IF-MIB::ifAdminStatus.3 = INTEGER: down(2)
  IF-MIB::ifAdminStatus.4 = INTEGER: down(2)
  IF-MIB::ifOperStatus.1 = INTEGER: up(1)
  IF-MIB::ifOperStatus.2 = INTEGER: up(1)
  IF-MIB::ifOperStatus.3 = INTEGER: down(2)
  IF-MIB::ifOperStatus.4 = INTEGER: down(2)
  IF-MIB::ifInOctets.1 = Counter32: 381118
  IF-MIB::ifInOctets.2 = Counter32: 125019173
  IF-MIB::ifInOctets.3 = Counter32: 0
  IF-MIB::ifInOctets.4 = Counter32: 0
  IF-MIB::ifInUcastPkts.1 = Counter32: 4308
  IF-MIB::ifInUcastPkts.2 = Counter32: 1069602
  IF-MIB::ifInUcastPkts.3 = Counter32: 0
  IF-MIB::ifInUcastPkts.4 = Counter32: 0
  IF-MIB::ifInDiscards.1 = Counter32: 0
  IF-MIB::ifInDiscards.2 = Counter32: 0
  IF-MIB::ifInDiscards.3 = Counter32: 0
  IF-MIB::ifInDiscards.4 = Counter32: 0
  IF-MIB::ifInErrors.1 = Counter32: 0
  IF-MIB::ifInErrors.2 = Counter32: 0
  IF-MIB::ifInErrors.3 = Counter32: 0
  IF-MIB::ifInErrors.4 = Counter32: 0
  IF-MIB::ifOutOctets.1 = Counter32: 383414
  IF-MIB::ifOutOctets.2 = Counter32: 1770179210
  IF-MIB::ifOutOctets.3 = Counter32: 0
  IF-MIB::ifOutOctets.4 = Counter32: 0
  IF-MIB::ifOutUcastPkts.1 = Counter32: 4340
  IF-MIB::ifOutUcastPkts.2 = Counter32: 1319881
  IF-MIB::ifOutUcastPkts.3 = Counter32: 0
  IF-MIB::ifOutUcastPkts.4 = Counter32: 0
  IF-MIB::ifOutDiscards.1 = Counter32: 0
  IF-MIB::ifOutDiscards.2 = Counter32: 0
  IF-MIB::ifOutDiscards.3 = Counter32: 0
  IF-MIB::ifOutDiscards.4 = Counter32: 0
  IF-MIB::ifOutErrors.1 = Counter32: 0
  IF-MIB::ifOutErrors.2 = Counter32: 0
  IF-MIB::ifOutErrors.3 = Counter32: 0
  IF-MIB::ifOutErrors.4 = Counter32: 0
  IF-MIB::ifOutQLen.1 = Gauge32: 0
  IF-MIB::ifOutQLen.2 = Gauge32: 0
  IF-MIB::ifOutQLen.3 = Gauge32: 0
  IF-MIB::ifOutQLen.4 = Gauge32: 0
  IF-MIB::ifSpecific.1 = OID: SNMPv2-SMI::zeroDotZero
  IF-MIB::ifSpecific.2 = OID: SNMPv2-SMI::zeroDotZero
  IF-MIB::ifSpecific.3 = OID: SNMPv2-SMI::zeroDotZero
  IF-MIB::ifSpecific.4 = OID: SNMPv2-SMI::zeroDotZero
  
  sh$ snmpget -v2c -c demo 192.168.0.98 IF-MIB::ifDescr.1
  IF-MIB::ifDescr.1 = STRING: lo
  sh$ snmpget -v2c -c demo 192.168.0.98 IF-MIB::ifDescr.2
  IF-MIB::ifDescr.2 = STRING: eth0
  sh$ snmpgetnext -v2c -c demo 192.168.0.98 IF-MIB::ifDescr.2
  IF-MIB::ifDescr.3 = STRING: eth1
那麼最初的配置有什麼問題呢?
無論如何,為安全起見,只做如下的 access:
  sh$ snmptranslate .1.3.6.1.2.1
  SNMPv2-SMI::mib-2
  sh$ snmptranslate -Of .1.3.6.1.2.1
  .iso.org.dod.internet.mgmt.mib-2
  
  sh$ cat /etc/snmp/snmpd.conf
  view    system       included       .1.3.6.1.2.1
  access  mynet "" any  noauth  exact  system  none  none
《解決方案》

謝謝分享




[火星人 via ] SNMP base(轉個普及貼)已經有371次圍觀

http://www.coctec.com/docs/service/show-post-1123.html