[Embedded linux] SNMP 移植完整教程

前言

目前我的想法是

  1. 先找 snmp packages 並嘗試透過 cross-compiler build snmp packages
  2. 使用 pc build 一版 x86 版本的 snmpd
  3. 學習 PC 如何透過 snmp client 來驗證 snmpd

本文目前只有詳細介紹第1點

snmp for arm-linux platform

準備工作

  1. 下載 net-snmp 5.8 source code package
  2. 透過 cross-compiler build snmpd binary
  3. 學習 snmpd.conf 的設定
  4. 移植到 arm-linux 進行測試
  5. 遇到問題與除錯方法
  6. 使用 snmp client 來驗證正確

1. 下載 net-snmp 5.8 source code package

2. 透過 cross-compiler build snmpd binary

目前我參考的 porting 網站有許多,覺得這個最好

configure 的 option

  • 如下表所示 (其他的要去 manpage 查詢)
options details
--host=arm-linux 運行平台
--target=arm-linux 目標平台
--build=i686-linux 編譯平台
--with-cc=arm-linux-gcc cross-compiler tool
--with-ar=arm-linux-ar 打包工具
--prefix=/usr/local/net-snmp 安裝目錄
--disable-shared 不編譯共享庫
--disable-scripts 不要安裝 mib2c 等版本
--with-endianness=little using little endian
--enable-mini-agent 最小化構建 agent
--disable-deprecated 不編譯放棄使用的功能
--without-logfile 指定 snmpd 不輸出 log 文件 (可以使用 --with-logfile 指定默認 log 檔案的位置)
--disable-minimalist 刪除所有非基本的代碼功能
--enable-debugging 打開除錯訊息
--disable-testing-code 不使用測試代碼 (某些代碼不被使用)
--with-openssl=/opt/hardhat openssl library 路徑 (支援加密)
--disable-ipv6 不使用 ipv6
--disable-manuals 不安裝 manpage 說明頁
--disable-ucd-snmp-compatibility 不需要相容 ucd-snmp
--disable-snmptrapd-subagent 不需要支援 snmptrapd 的子代理
--disable-embedded-perl 在 snmp agent 和 snmptrapd 禁用 embedded perl 預設啟用
--disable-applications 是否關閉 snmpget 等功能,根據自己的需求選擇
--with-default-snmp-version="3" 指定預設 snmp protocal version
--enable-as-needed 僅鏈接需要的library
  • 根據以上,我組態設定為
    1
    ./configure --prefix=/var/net-snmp --build=i686-linux --host=arm-linux --with-default-snmp-version="2" --with-sys-contact="timmyliu@weintek.com" --with-sys-location="location" --with-logfile="/var/log/snmpd.log" --with-copy-persistent-files="no" --without-opaque-special-types --without-rpm --without-perl-modules --disable-manuals --disable-ipv6 --disable-ucd-snmp-compatibility --disable-embedded-perl --disable-snmptrapd-subagent --disable-scripts -enable-mfd-rewrites --enable-shared=no --enable-mini-agent --with-cc=arm-none-linux-gnueabi-gcc --with-ar=arm-none-linux-gnueabi-ar

看不清所有設定的話,可以寫成:

1
2
3
4
5
6
7
8
9
10
11
./configure --prefix=/var/net-snmp \
--build=i686-linux --host=arm-linux \
--with-default-snmp-version="2" --with-sys-contact="timmyliu@weintek.com" \
--with-sys-location="location" --with-logfile="/var/log/snmpd.log" \
--with-copy-persistent-files="no" --without-opaque-special-types \
--without-rpm --without-perl-modules \
--disable-manuals --disable-ipv6 --disable-ucd-snmp-compatibility \
--disable-embedded-perl --disable-snmptrapd-subagent --disable-scripts \
-enable-mfd-rewrites --enable-shared=no --enable-mini-agent \
--with-cc=arm-none-linux-gnueabi-gcc \
--with-ar=arm-none-linux-gnueabi-ar

  • configure summary
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ---------------------------------------------------------
    Net-SNMP configuration summary:
    ---------------------------------------------------------

    SNMP Versions Supported: 1 2c 3
    Building for: linux
    Net-SNMP Version: 5.8
    Network transport support: Callback Unix Alias TCP UDP IPv4Base SocketBase TCPBase UDPIPv4Base UDPBase
    SNMPv3 Security Modules: usm
    Agent MIB code: default_modules => snmpv3mibs mibII/snmp_mib mibII/system_mib mibII/sysORTable mibII/vacm_vars mibII/vacm_conf
    MYSQL Trap Logging: unavailable
    Embedded Perl support: disabled
    SNMP Perl modules: disabled
    SNMP Python modules: disabled
    Crypto support from: internal
    Authentication support: MD5 SHA1
    Encryption support: DES AES
    Local DNSSEC validation: disabled

    ---------------------------------------------------------

之後就執行 make

  • 如果之前有 build 過的話就執行 make clean && make
  • build 成功的話會看到下面兩行

    1
    2
    chmod a+x net-snmp-config
    touch net-snmp-config-x
  • 透過 ll -h agent/snmpd 看一下 size

    1
    2
    weintek-timmy@weintek-timmy:~/Timmy/GitHub/net-snmp-5.8$ ll -h agent/snmpd
    -rwxrwxr-x 1 weintek-timmy weintek-timmy 2.3M 12月 4 15:58 agent/snmpd*

使用strip進行程式瘦身

看你是 soft-float 還是 hard-float compiler,以這個例子我們是使用 arm-none-linux-gnueabi-來編譯,那我們就使用 arm-none-linux-gnueabi-strip來瘦身

1
2
3
4
weintek-timmy@weintek-timmy:~/Timmy/GitHub/net-snmp-5.8$ arm-none-linux-gnueabi-strip agent/snmpd
weintek-timmy@weintek-timmy:~/Timmy/GitHub/net-snmp-5.8$ ll -h agent/snmpd
-rwxrwxr-x 1 weintek-timmy weintek-timmy 696K 124 16:04 agent/snmpd*
weintek-timmy@weintek-timmy:~/Timmy/GitHub/net-snmp-5.8$

從 2.3M 瘦身成 696K

3. 學習 snmpd.conf 的設定

具體配置方式可以參考這裡的第五部份,然而我會從那個網站中將設定的方式紀錄於此

  • 複製 EXAMPLE.conf 到原本的資料夾中,用此製作一份新的 config file

    1
    cp EXAMPLE.conf snmpd.conf
  • 開啟外網 access 權限

原本預設的 snmpd.conf 通常都是使用 localhost (127.0.0.1),如果要使用外網訪問的話,就要修改

1
2
3
4
5
6
#    AGENT BEHAVIOUR
#
# Listen for connections from the local system only
# agentAddress udp:127.0.0.1:161
# Listen for connections on all interfaces (both IPv4 *and* IPv6)
agentAddress udp:161,udp6:[::1]:161

如果把 #agentAddress upd:127.0.0.1:161 解開的話就會變成使用 localhost listen

  • 設定共同體名稱 (community)

我們使用 EXAMPLE.conf 中的 com2sec/group/view/access 的說明,大約是預設文件的第 65 行

首先我們定義一個首共同體名稱(community),這裡我們使用 public,以及可以訪問這個 public 的用戶名(sec name),這裡是 notConfigUser。public 相當於用戶 notConfigUser 的密碼

在 snmpd.conf 檔案中加入以下 (可使用 “#” 來加入註解)

1
2
#        sec.name        source    community
com2sec notConfigUser default public

  • 定義 gpoup 名稱 (組名)

之後我們定義一個組名 (groupName) 這裡是 notConfigGroup,以及 group 的安全級別(也就是 snmp version) 並把 notConfigUser 這個用戶加到這個 group 中。

在 snmpd.conf 檔案中加入以下

1
2
3
#       groupName       securityModel    securityName
group notConfigGroup v1 notConfigUser
group notConfigGroup v2c notConfigUser

  • 定義可試圖 (view) 名稱

我們加入 all 這個名稱,可視範圍為 .1,在 snmpd.conf 檔案中加入以下

1
2
#       name     incl/excl     subtree      mask(optional)
view all included .1

並且註解

1
2
view   systemonly  included   .1.3.6.1.2.1.1
view systemonly included .1.3.6.1.2.1.25.1

  • 定義可試圖操作

最後定義 notConfigUser 這個組在 all 這個可視圖中內可做的操作,我們在此定義了 notConfigGroup 內的成員可以對 .1 這個可視範圍做 「唯讀」 操作。

1
2
#          group        context sec.model  sec.level  prefix read   write  notif
access notConfigGroup "" any noauth exact all none none

接下來設置系統資訊

  • 設置區域

    1
    sysLocation    "New Taipei City, Taiwan"
  • 設置聯絡人

    1
    sysContact     Me <me@example.org>
  • 設置監控主機

    1
    2


  • 設置讀寫帳戶
    conf=

    1
    2
    3
    4
    5
    6
    ### 4. 移植到 arm-linux 進行測試

    * 先從 agent 目錄下 copy 出 snmpd 執行檔
    * 在 embedded-linux 目標機器上創建 snmpd.conf 的設定文件 (我習慣在PC上面先建置好再透過 `scp` 拷貝到裝置內)
    ```sh=
    scp agent/snmpd snmp.conf root@192.168.2.98:/root/
  • 之後執行 ./snmpd -c snmpd.conf –f –Le –d (大部份都要除錯,很少第一次成功)

5. 除錯與問題處理

遇到 cannot file module 與 snmpd.conf: unknown token 的問題

執行時遇到問題

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@cMT-15C2 /root]# ./snmpd -c snmpd.conf -f -Le -d
Created directory: /var/net-snmp
Created directory: /var/net-snmp/mib_indexes
MIB search path: /root/.snmp/mibs:/var/net-snmp/share/snmp/mibs
Cannot find module (SNMPv2-MIB): At line 0 in (none)
Cannot find module (IF-MIB): At line 0 in (none)
Cannot find module (IP-MIB): At line 0 in (none)
Cannot find module (TCP-MIB): At line 0 in (none)
Cannot find module (UDP-MIB): At line 0 in (none)
Cannot find module (SNMP-VIEW-BASED-ACM-MIB): At line 0 in (none)
Cannot find module (SNMP-COMMUNITY-MIB): At line 0 in (none)
Cannot find module (SNMP-FRAMEWORK-MIB): At line 0 in (none)
Cannot find module (SNMP-MPD-MIB): At line 0 in (none)
Cannot find module (SNMP-USER-BASED-SM-MIB): At line 0 in (none)
snmpd.conf: line 96: Warning: Unknown token: proc.
snmpd.conf: line 98: Warning: Unknown token: proc.
snmpd.conf: line 100: Warning: Unknown token: proc.
snmpd.conf: line 110: Warning: Unknown token: disk.
snmpd.conf: line 111: Warning: Unknown token: disk.
snmpd.conf: line 112: Warning: Unknown token: includeAllDisks.
snmpd.conf: line 122: Warning: Unknown token: load.
snmpd.conf: line 149: Warning: Unknown token: iquerySecName.
snmpd.conf: line 152: Warning: Unknown token: defaultMonitors.
snmpd.conf: line 154: Warning: Unknown token: linkUpDownNotifications.
snmpd.conf: line 166: Warning: Unknown token: extend.
snmpd.conf: line 167: Warning: Unknown token: extend-sh.
snmpd.conf: line 199: Warning: Unknown token: master.
Error opening specified endpoint "udp:161"
Server Exiting with code 1

這個問題分兩部份

  • Cannot find module…
  • snmpd.conf: line …: Warning: Unknown token: …
處理 snmpd.conf: line ...: Warning: Unknown token: ... 的問題

如果仔細去看他的 warning 的話,其實很簡單,他就是認不出這些設定檔,原因是因為這些設定可能因為執行 ./configure 的時候 disable 掉了,反正不設他就會使用預設的參數,所以我們就全部註解掉

  1. 將 proc 的設定註解
  2. 將 disk / includeAllDisks 註解
  3. 將 load 註解
  4. 將 iquerySecName / defaultMonitors / linkUpDownNotifications 註解
  5. 將 extend / extend-sh / master 註解
  6. 將 trapsink 註解

傳到裝置上再執行一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@cMT-15C2 /root]# ./snmpd -c snmpd.conf -f -Le -d
MIB search path: /root/.snmp/mibs:/var/net-snmp/share/snmp/mibs
Cannot find module (SNMPv2-MIB): At line 0 in (none)
Cannot find module (IF-MIB): At line 0 in (none)
Cannot find module (IP-MIB): At line 0 in (none)
Cannot find module (TCP-MIB): At line 0 in (none)
Cannot find module (UDP-MIB): At line 0 in (none)
Cannot find module (SNMP-VIEW-BASED-ACM-MIB): At line 0 in (none)
Cannot find module (SNMP-COMMUNITY-MIB): At line 0 in (none)
Cannot find module (SNMP-FRAMEWORK-MIB): At line 0 in (none)
Cannot find module (SNMP-MPD-MIB): At line 0 in (none)
Cannot find module (SNMP-USER-BASED-SM-MIB): At line 0 in (none)
Error opening specified endpoint "udp:161"
Server Exiting with code 1
處理 cannot find module 問題

問題點從 message 就大概可以知道 MIB module 需要匯入,而路徑是 /var/net-snmp/share/snmp/mibs

所以我們就先建立新的資料夾

1
mkdir -p /var/net-snmp/share/snmp/mibs

然後進入 PC source code 的 mibs 將裏面的 module 撈出來給裝置

1
2
3
cd ~net-snmp-5.8/mibs

scp * root@192.168.2.98:/var/net-snmp/share/snmp/mibs/

再執行一次

1
2
3
[root@cMT-15C2 /root]# ./snmpd -c snmpd.conf -f -Le -d
Error opening specified endpoint "udp:161"
Server Exiting with code 1

還有最後一個問題

處理 Error opening specified endpoint “udp:161”

因為我們之前使用 ./configure 的時候加入了一個參數 --disable-ipv6 ,所以我們必須將 udp的 ipv6設定移掉
修改 snmpd.conf ,將 udp6:[::1]:161 移掉

1
2
# orig: agentAddress udp:161,udp6:[::1]:161
agentAddress udp:161

還有其他可能性,但大部份都是 conf 檔要放對位置

6. 使用 snmp client 來驗證正確

若使用指令 ./snmpd -c snmpd.conf -f -Le -d 啟動之後出現 NET-SNMP version 5.8 表示已經運行,這時候我們使用 snmpwalk 試試看

  • PC 端:

    • 1
      2
      snmpget -v 2c -c public 192.168.2.98 sysDescr.0
      SNMPv2-MIB::sysDescr.0 = STRING: Linux cMT-15C2 4.1.15+ #629 PREEMPT Fri Aug 10 18:14:50 CST 2018 armv7l
  • 裝置端:

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      Received 43 byte packet from UDP: [192.168.1.21]:59770->[192.168.2.98]:161
      0000: 30 29 02 01 01 04 06 70 75 62 6C 69 63 A0 1C 02 0).....public...
      0016: 04 12 1B C8 08 02 01 00 02 01 00 30 0E 30 0C 06 ...........0.0..
      0032: 08 2B 06 01 02 01 01 01 00 05 00 .+.........


      Sending 114 bytes to UDP: [192.168.1.21]:59770->[192.168.2.98]:161
      0000: 30 70 02 01 01 04 06 70 75 62 6C 69 63 A2 63 02 0p.....public.c.
      0016: 04 12 1B C8 08 02 01 00 02 01 00 30 55 30 53 06 ...........0U0S.
      0032: 08 2B 06 01 02 01 01 01 00 04 47 4C 69 6E 75 78 .+........GLinux
      0048: 20 63 4D 54 2D 31 35 43 32 20 34 2E 31 2E 31 35 cMT-15C2 4.1.15
      0064: 2B 20 23 36 32 39 20 50 52 45 45 4D 50 54 20 46 + #629 PREEMPT F
      0080: 72 69 20 41 75 67 20 31 30 20 31 38 3A 31 34 3A ri Aug 10 18:14:
      0096: 35 30 20 43 53 54 20 32 30 31 38 20 61 72 6D 76 50 CST 2018 armv
      0112: 37 6C

我們可以再寫一個 snmpwalk 來抓取系統狀態

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
weintek-timmy@weintek-timmy:~$ snmpwalk -v 1 192.168.2.98 -c public system
SNMPv2-MIB::sysDescr.0 = STRING: Linux cMT-15C2 4.1.15+ #629 PREEMPT Fri Aug 10 18:14:50 CST 2018 armv7l
SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (55157) 0:09:11.57
SNMPv2-MIB::sysContact.0 = STRING: Me <me@example.org>
SNMPv2-MIB::sysName.0 = STRING: cMT-15C2
SNMPv2-MIB::sysLocation.0 = STRING: \"New Taipei City, Taiwan\"
SNMPv2-MIB::sysServices.0 = INTEGER: 72
SNMPv2-MIB::sysORLastChange.0 = Timeticks: (0) 0:00:00.00
SNMPv2-MIB::sysORID.1 = OID: SNMPv2-MIB::snmpMIB
SNMPv2-MIB::sysORID.2 = OID: SNMP-VIEW-BASED-ACM-MIB::vacmBasicGroup
SNMPv2-MIB::sysORID.3 = OID: SNMP-FRAMEWORK-MIB::snmpFrameworkMIBCompliance
SNMPv2-MIB::sysORID.4 = OID: SNMP-MPD-MIB::snmpMPDCompliance
SNMPv2-MIB::sysORID.5 = OID: SNMP-USER-BASED-SM-MIB::usmMIBCompliance
SNMPv2-MIB::sysORDescr.1 = STRING: The MIB module for SNMPv2 entities
SNMPv2-MIB::sysORDescr.2 = STRING: View-based Access Control Model for SNMP.
SNMPv2-MIB::sysORDescr.3 = STRING: The SNMP Management Architecture MIB.
SNMPv2-MIB::sysORDescr.4 = STRING: The MIB for Message Processing and Dispatching.
SNMPv2-MIB::sysORDescr.5 = 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: (0) 0:00:00.00
SNMPv2-MIB::sysORUpTime.3 = Timeticks: (0) 0:00:00.00
SNMPv2-MIB::sysORUpTime.4 = Timeticks: (0) 0:00:00.00
SNMPv2-MIB::sysORUpTime.5 = Timeticks: (0) 0:00:00.00

SNMP OID 使用

我們使用 snmpwalk 來取得目前 mib 可以使用的 module
只要輸入 snmpwalk -v 2c -c public 192.168.2.98 就可以 printf 出可以獲得的訊息

Linux 常用的 OID

Load

function OID
1 minute Load .1.3.6.1.4.1.2021.10.1.3.1
5 minute Load .1.3.6.1.4.1.2021.10.1.3.2
15 minute Load .1.3.6.1.4.1.2021.10.1.3.3

CPU

function OID
percentage of user CPU time .1.3.6.1.4.1.2021.11.9.0
raw user cpu time .1.3.6.1.4.1.2021.11.50.0
percentages of system CPU time .1.3.6.1.4.1.2021.11.10.0
raw system cpu time .1.3.6.1.4.1.2021.11.52.0
percentages of idle CPU time .1.3.6.1.4.1.2021.11.11.0
raw idle cpu time .1.3.6.1.4.1.2021.11.53.0
raw nice cpu time .1.3.6.1.4.1.2021.11.51.0

內部儲存資訊

function OID
Total Swap Size .1.3.6.1.4.1.2021.4.3.0
Available Swap Space .1.3.6.1.4.1.2021.4.4.0
Total RAM in machine .1.3.6.1.4.1.2021.4.5.0
Total RAM used .1.3.6.1.4.1.2021.4.6.0
Total RAM Free .1.3.6.1.4.1.2021.4.11.0
Total RAM Shared .1.3.6.1.4.1.2021.4.13.0
Total RAM Buffered .1.3.6.1.4.1.2021.4.14.0
Total Cached Memory .1.3.6.1.4.1.2021.4.15.0

Disk 相關

The snmpd.conf needs to be edited. Add the following (assuming a machine with a single ‘/’ partition):
disk / 100000 (or)
includeAllDisks 10% for all partitions and disks
The OIDs are as follows

function OID
Path where the disk is mounted .1.3.6.1.4.1.2021.9.1.2.1
Path of the device for the partition .1.3.6.1.4.1.2021.9.1.3.1
Total size of the disk/partion (kBytes) .1.3.6.1.4.1.2021.9.1.6.1
Available space on the disk .1.3.6.1.4.1.2021.9.1.7.1
Used space on the disk .1.3.6.1.4.1.2021.9.1.8.1
Percentage of space used on disk .1.3.6.1.4.1.2021.9.1.9.1
Percentage of inodes used on disk .1.3.6.1.4.1.2021.9.1.10.1

系統運行時間

function OID
System Uptime .1.3.6.1.2.1.1.3.0

PS: linux 系统也可直接用 uptime 命令獲得系統資訊

網路設備相關

function OID 功能說明
ifIndex 1.3.6.1.2.1.2.2.1.1.0 端口索引編號
ifDescr 1.3.6.1.2.1.2.2.1.2.0 端口描述
ifType 1.3.6.1.2.1.2.2.1.3.0 端口類型
ifMtu 1.3.6.1.2.1.2.2.1.4.0 最大傳輸封包字節數
ifSpeed 1.3.6.1.2.1.2.2.1.5.0 端口速度
ifPhysAddress 1.3.6.1.2.1.2.2.1.6.0 MAC address
ifOperStatus 1.3.6.1.2.1.2.2.1.8.0 操作狀態
ifLastChange 1.3.6.1.2.1.2.2.1.9.0 上次狀態更新時間
ifInOctets 1.3.6.1.2.1.2.2.1.10.0 輸入字節數
ifInUcastPkts 1.3.6.1.2.1.2.2.1.11.0 輸入非廣播封包數
ifInNUcastPkts 1.3.6.1.2.1.2.2.1.12.0 輸入廣播封包數
ifInDiscards 1.3.6.1.2.1.2.2.1.13.0 輸入封包丟棄數
ifInErrors 1.3.6.1.2.1.2.2.1.14.0 輸入封包錯誤數
ifInUnknownProtos 1.3.6.1.2.1.2.2.1.15.0 輸入未知協議封包數
ifOutOctets 1.3.6.1.2.1.2.2.1.16.0 輸出字節數
ifOutUcastPkts 1.3.6.1.2.1.2.2.1.17.0 輸出非廣播封包數
ifOutNUcastPkts 1.3.6.1.2.1.2.2.1.18.0 輸出廣播封包數
ifOutDiscards 1.3.6.1.2.1.2.2.1.19.0 輸出封包丟棄數
ifOutErrors 1.3.6.1.2.1.2.2.1.20.0 輸出封包錯誤數
ifOutQLen 1.3.6.1.2.1.2.2.1.21.0 output queue size

流量輸出是用計數器,數目會改變,單位是 byte, 32 位
如果流量大過出現土寄不正確的情形,就需要在編譯時加上 enable-mfd-rewrites 參數,來支援 64 位的計數器

reference