2014/12/29

話務量 電話流量單位 erlang

erlang 是話務量的單位,簡單地說,是表示每小時連續的總通話長度數量,我們可根據此話務量的數值,作為設計電話通訊網路流量的規模參考數值。

由來

在 1946 年,CCITT(International Telegraph and Telephone Consultative Committee) 也就是現在的 ITU-T (International Telecommunication Union-Telecommunication Standardization Sector) 將電話話務流量命名為 erlang,命名來自丹麥數學家及統計學家 Agner Krarup Erlang。

A.K. Erlang 是在 1878 年出生於丹麥,是電信流量理論的專家,在 1909年發表了第一個著作: The Theory of Probabilities and Telephone Conversations。1929年過世後,到了1940年代,erlang 這個電信流量計算公式被大家廣為接受。

erlang 計算範例

如果一條電話線被佔用 1 小時,話務量就是 1 erlang。
如果一條電話線被佔用 0.5 小時,話務量是 0.5 erlang。

假設有一組使用者,在一個小時內產生了30通電話,平均每一通電話持續了 5 分鐘,那麼 erlang 值可以按照以下步驟計算:

  1. 一小時內的電話流量總時間 = 通話數量 (BHCA) X 平均每一通電話的通話時間 (Holding Time, hrs)
  2. 通話數量為 30
  3. 平均每一通電話的通話時間為 5/60 (hrs)
  4. 30 * 5 / 60 = 2.5

因此在這個範例中,erlang 值就是 2.5。

Traffic Models

當取得 erlang 數值後,就可以套用到話務模型中,用以計算電話系統必須要提供幾條外撥線路給這一群使用者使用。

目前有三種話務模型,其中以 Erlang B 最為常被使用

  1. Erlang B
  2. Extended Erlang B
  3. Erlang C

Erlang B 有三個參數

  1. BHT: Busy Hour Traffic (in Erlangs)
    這就是剛剛計算出來的 erlang 數值,要以此電話系統最忙碌的那一個小時內的資料,計算出此 erlang 數值。
  2. Blocking
    這是因為外撥線路不足,發生無法外撥電話的錯誤通話數,如果是0.01,就表示每 100 通電話,會發生 1 次無法外撥電話的錯誤。
  3. Lines
    就是我們需要知道的計算結果,在這一組電話系統中,要提供幾條外撥線路的數量。

Erlang B 線上計算頁面 可計算出結果,如果是以 BHT = 2.5,Blocking = 0.01 去計算,可得到 Lines 結果為 7 。

Trunking 中繼

Trunking 中繼是兩點間的一條傳輸通道,通常兩點都是電話交換中心。Trunking 在以前是利用實體線路將兩點連接起來,隨著科技發展,中繼的概念不僅應用於無線通信中,基於網際網路的電信交換機的trunk也可以稱為一種中繼。

Erlang Traffic Model 中計算得到的結果 Lines,就是用在連接兩個電話交換中心之間的 trunking 能夠支援的同時通話線路數量。

參考資料

  1. wiki: Erlang (unit)
  2. What is erlang
  3. 話務量
  4. 什麼是Erlang B公式,什麼是Erlang C公式?

2014/12/22

如何使用 snmp4j 處理 trap

以下以 snmp4j 套件提供處理 trap 的範例。

multithread trap receiver

trap receiver 必須在本機建立一個 UDP Port 162 的 server,一直等待 client 端發送 UDP trap,在處理這樣的 server時,multithread 是必要的。

程式範例

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Iterator;
import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snmp4j.CommandResponder;
import org.snmp4j.CommandResponderEvent;
import org.snmp4j.MessageDispatcherImpl;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.MPv3;
import org.snmp4j.security.AuthMD5;
import org.snmp4j.security.PrivDES;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.TcpAddress;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;

public class SNMPTrapReceiver implements CommandResponder {
    public static Logger logger = LoggerFactory
            .getLogger(SNMPTrapReceiver.class.getName());

    private MultiThreadedMessageDispatcher dispatcher;
    private Snmp snmp = null;
    private Address listenAddress;
    private ThreadPool threadPool;
    private int n = 0;
    private long start = -1;

    public SNMPTrapReceiver() {
    }

    public static void main(String[] args) {
        new SNMPTrapReceiver().run();
    }

    private void run() {
        try {
            init();
            snmp.addCommandResponder(this);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void init() throws UnknownHostException, IOException {
        threadPool = ThreadPool.create("Trap", 10);
        dispatcher = new MultiThreadedMessageDispatcher(threadPool,
                new MessageDispatcherImpl());
        listenAddress = GenericAddress.parse(System.getProperty(
                "snmp4j.listenAddress", "udp:0.0.0.0/162"));
        TransportMapping<?> transport;
        if (listenAddress instanceof UdpAddress) {
            transport = new DefaultUdpTransportMapping(
                    (UdpAddress) listenAddress);
        } else {
            transport = new DefaultTcpTransportMapping(
                    (TcpAddress) listenAddress);
        }
        USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(
                MPv3.createLocalEngineID()), 0);
        usm.setEngineDiscoveryEnabled(true);

        snmp = new Snmp(dispatcher, transport);
        snmp.getMessageDispatcher().addMessageProcessingModel(new MPv1());
        snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c());
        snmp.getMessageDispatcher().addMessageProcessingModel(new MPv3(usm));
        SecurityModels.getInstance().addSecurityModel(usm);
        snmp.getUSM().addUser(
                new OctetString("MD5DES"),
                new UsmUser(new OctetString("MD5DES"), AuthMD5.ID,
                        new OctetString("UserName"), PrivDES.ID,
                        new OctetString("PasswordUser")));
        snmp.getUSM().addUser(new OctetString("MD5DES"),
                new UsmUser(new OctetString("MD5DES"), null, null, null, null));

        snmp.listen();
    }

    public void processPdu(CommandResponderEvent event) {
        if (start < 0) {
            start = System.currentTimeMillis() - 1;
        }
        n++;
        if ((n % 100 == 1)) {
            logger.info("Processed "
                    + (n / (double) (System.currentTimeMillis() - start))
                    * 1000 + "/s, total=" + n);
        }

        StringBuffer msg = new StringBuffer();
        msg.append(event.toString());
        Vector<? extends VariableBinding> varBinds = event.getPDU()
                .getVariableBindings();
        if (varBinds != null && !varBinds.isEmpty()) {
            Iterator<? extends VariableBinding> varIter = varBinds.iterator();
            while (varIter.hasNext()) {
                VariableBinding var = varIter.next();
                msg.append(var.toString()).append(";");
            }
        }
        logger.info("Message Received: " + msg.toString());
    }
}

這是發送 trap 的範例,有區分 snmp v1, v2c, v3 三種協定。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snmp4j.CommandResponder;
import org.snmp4j.CommandResponderEvent;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.ScopedPDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.UserTarget;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.SecurityLevel;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.IpAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.DefaultPDUFactory;

public class SNMPTrapGeneratorClient {
    public static Logger logger = LoggerFactory
            .getLogger(SNMPTrapGeneratorClient.class.getName());

    private static final String community = "public";
    private static final String trapOid = ".1.3.6.1.2.1.1.6";
    private static final String ipAddress = "127.0.0.1";
    private static final int port = 162;

    public static void main(String args[]) {
        sendSnmpV1V2Trap(SnmpConstants.version1);
        sendSnmpV1V2Trap(SnmpConstants.version2c);
        sendSnmpV3Trap();
    }

    /**
     * This methods sends the V1/V2 trap
     * 
     * @param version
     */
    private static void sendSnmpV1V2Trap(int version) {
        // send trap
        sendV1orV2Trap(version, community, ipAddress, port);
    }

    private static PDU createPdu(int snmpVersion) {
        PDU pdu = DefaultPDUFactory.createPDU(snmpVersion);
        if (snmpVersion == SnmpConstants.version1) {
            pdu.setType(PDU.V1TRAP);
        } else {
            pdu.setType(PDU.TRAP);
        }
        pdu.add(new VariableBinding(SnmpConstants.sysUpTime));
        pdu.add(new VariableBinding(SnmpConstants.snmpTrapOID, new OID(trapOid)));
        pdu.add(new VariableBinding(SnmpConstants.snmpTrapAddress,
                new IpAddress(ipAddress)));
        pdu.add(new VariableBinding(new OID(trapOid), new OctetString("Major")));
        return pdu;
    }

    private static void sendV1orV2Trap(int snmpVersion, String community,
            String ipAddress, int port) {
        try {
            // create v1/v2 PDU
            PDU snmpPDU = createPdu(snmpVersion);

            // Create Transport Mapping
            TransportMapping<?> transport = new DefaultUdpTransportMapping();
            transport.listen();

            // Create Target
            CommunityTarget comtarget = new CommunityTarget();
            comtarget.setCommunity(new OctetString(community));
            comtarget.setVersion(snmpVersion);
            comtarget.setAddress(new UdpAddress(ipAddress + "/" + port));
            comtarget.setRetries(2);
            comtarget.setTimeout(5000);

            // Send the PDU
            Snmp snmp = new Snmp(transport);
            snmp.send(snmpPDU, comtarget);
            logger.info("Sent Trap to (IP:Port)=> " + ipAddress + ":" + port);
            snmp.close();
        } catch (Exception e) {
            logger.error("Error: ", e);
        }
    }

    /**
     * Sends the v3 trap
     */
    private static void sendSnmpV3Trap() {
        try {
            Address targetAddress = GenericAddress.parse("udp:" + ipAddress
                    + "/" + port);
            TransportMapping<?> transport = new DefaultUdpTransportMapping();
            Snmp snmp = new Snmp(transport);
            USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(
                    MPv3.createLocalEngineID()), 0);
            SecurityModels.getInstance().addSecurityModel(usm);
            transport.listen();

            snmp.getUSM().addUser(
                    new OctetString("MD5DES"),
                    new UsmUser(new OctetString("MD5DES"), null, null, null,
                            null));

            // Create Target
            UserTarget target = new UserTarget();
            target.setAddress(targetAddress);
            target.setRetries(1);
            target.setTimeout(11500);
            target.setVersion(SnmpConstants.version3);
            target.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
            target.setSecurityName(new OctetString("MD5DES"));

            // Create PDU for V3
            ScopedPDU pdu = new ScopedPDU();
            pdu.setType(ScopedPDU.NOTIFICATION);
            pdu.add(new VariableBinding(SnmpConstants.sysUpTime));
            pdu.add(new VariableBinding(SnmpConstants.snmpTrapOID,
                    SnmpConstants.linkDown));
            pdu.add(new VariableBinding(new OID(trapOid), new OctetString(
                    "Major")));

            // Send the PDU
            snmp.send(pdu, target);
            logger.info("Sending Trap to (IP:Port)=> " + ipAddress + ":"
                    + port);
            snmp.addCommandResponder(new CommandResponder() {
                public void processPdu(CommandResponderEvent arg0) {
                    logger.info(arg0);
                }
            });
            snmp.close();
        } catch (Exception e) {
            logger.error("Error: ", e);
        }
    }
}

執行結果

trap 發送端,很單純地就直接把 trap 送出去

2014-12-08 10:43:51,195 [main] INFO  SNMPTrapGeneratorClient 91
 Sent Trap to (IP:Port)=> 127.0.0.1:162
2014-12-08 10:43:51,204 [main] INFO  SNMPTrapGeneratorClient 91
 Sent Trap to (IP:Port)=> 127.0.0.1:162
2014-12-08 10:43:51,224 [main] INFO  SNMPTrapGeneratorClient 137
 Sending Trap to (IP:Port)=> 127.0.0.1:162

trap 接收端

2014-12-08 10:43:51,279 [Trap.1] INFO  SNMPTrapReceiver 102
 Processed 1000.0/s, total=2
2014-12-08 10:43:51,279 [Trap.0] INFO  SNMPTrapReceiver 118
 Message Received: CommandResponderEvent[securityModel=1, securityLevel=1, maxSizeResponsePDU=65535, pduHandle=PduHandle[0], stateReference=StateReference[msgID=0,pduHandle=PduHandle[0],securityEngineID=null,securityModel=null,securityName=public,securityLevel=1,contextEngineID=null,contextName=null,retryMsgIDs=null], pdu=V1TRAP[reqestID=0,timestamp=0:00:00.00,enterprise=0.0,genericTrap=0,specificTrap=0, VBS[1.3.6.1.2.1.1.3.0 = Null; 1.3.6.1.6.3.1.1.4.1.0 = 1.3.6.1.2.1.1.6; 1.3.6.1.6.3.18.1.3.0 = 127.0.0.1; 1.3.6.1.2.1.1.6 = Major]], messageProcessingModel=0, securityName=public, processed=false, peerAddress=127.0.0.1/51136, transportMapping=org.snmp4j.transport.DefaultUdpTransportMapping@13fdb89, tmStateReference=null]1.3.6.1.2.1.1.3.0 = Null;1.3.6.1.6.3.1.1.4.1.0 = 1.3.6.1.2.1.1.6;1.3.6.1.6.3.18.1.3.0 = 127.0.0.1;1.3.6.1.2.1.1.6 = Major;
2014-12-08 10:43:51,286 [Trap.1] INFO  SNMPTrapReceiver 118
 Message Received: CommandResponderEvent[securityModel=2, securityLevel=1, maxSizeResponsePDU=65535, pduHandle=PduHandle[1338161657], stateReference=StateReference[msgID=0,pduHandle=PduHandle[1338161657],securityEngineID=null,securityModel=null,securityName=public,securityLevel=1,contextEngineID=null,contextName=null,retryMsgIDs=null], pdu=TRAP[requestID=1338161657, errorStatus=Success(0), errorIndex=0, VBS[1.3.6.1.2.1.1.3.0 = Null; 1.3.6.1.6.3.1.1.4.1.0 = 1.3.6.1.2.1.1.6; 1.3.6.1.6.3.18.1.3.0 = 127.0.0.1; 1.3.6.1.2.1.1.6 = Major]], messageProcessingModel=1, securityName=public, processed=false, peerAddress=127.0.0.1/51138, transportMapping=org.snmp4j.transport.DefaultUdpTransportMapping@13fdb89, tmStateReference=null]1.3.6.1.2.1.1.3.0 = Null;1.3.6.1.6.3.1.1.4.1.0 = 1.3.6.1.2.1.1.6;1.3.6.1.6.3.18.1.3.0 = 127.0.0.1;1.3.6.1.2.1.1.6 = Major;
2014-12-08 10:43:51,312 [Trap.2] INFO SNMPTrapReceiver 118
 Message Received: CommandResponderEvent[securityModel=3, securityLevel=1, maxSizeResponsePDU=65428, pduHandle=PduHandle[1828414888], stateReference=null, pdu=TRAP[{contextEngineID=80:00:13:70:01:c0:a8:01:39:e2:ca:22:3e, contextName=}, requestID=1828414888, errorStatus=0, errorIndex=0, VBS[1.3.6.1.2.1.1.3.0 = Null; 1.3.6.1.6.3.1.1.4.1.0 = 1.3.6.1.6.3.1.1.5.3; 1.3.6.1.2.1.1.6 = Major]], messageProcessingModel=3, securityName=MD5DES, processed=false, peerAddress=127.0.0.1/51139, transportMapping=org.snmp4j.transport.DefaultUdpTransportMapping@13fdb89, tmStateReference=null]1.3.6.1.2.1.1.3.0 = Null;1.3.6.1.6.3.1.1.4.1.0 = 1.3.6.1.6.3.1.1.5.3;1.3.6.1.2.1.1.6 = Major;

Reference

Trap Receiver

2014/12/15

如何使用 snmp4j 進行查詢

SNMP 的原理跟概念 分為 Agent 與 Client 兩端需要處理,如果不是提供機器與服務的,就不需要做 Agent 這個 Server,一般最基本的 SNMP 程式設計是撰寫 SNMP Client,Client 又有兩個部份 (1) SNMP GET, Walk (2) Trap Receiver,以下以 snmp4j 套件提供第一個部份 SNMP GET, Walk 的範例。

SNMP GET

給予 server ip,這邊刻意將程式區分為 connect, snmpget, close 三個部份,因為 UDP 本身是 connection less 的一種網路連線,未來在使用時,只要連結起來,應該就能持續發送 SNMP GET,並取得結果。

snmpGet 有兩種 method,第一種就單純地只接受一個 oid 參數,第二種,是接受一個 oid List,可一次查詢多個 oid 的結果。

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.Null;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.Variable;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;

public class SnmpGet {
    public static Logger logger = LoggerFactory.getLogger(SnmpGet.class
            .getName());

    private static int version = SnmpConstants.version1;
    private static String protocol = "udp";

    private static CommunityTarget target = null;
    private static DefaultUdpTransportMapping udpTransportMapping = null;
    private static Snmp snmp = null;

    public static void main(String[] args) {

        String ip = "192.168.1.8";
        String community = "public";
        int port = 161;

        Variable var = null;
        SnmpGet tester = new SnmpGet();
        // tester.snmpGet(ip, port, community, oidval);
        try {
            tester.connect(ip, port, community);
            // System Uptime(系統運行時間) 的 oid, 最前面的 . 可以忽略不寫
            String oid = ".1.3.6.1.2.1.1.3.0";
            var = tester.snmpGet(oid);
            logger.info(oid + " = " + var);

            Thread.sleep(3 * 1000);
            logger.info("");
            oid = ".1.3.6.1.2.1.1.1.0";
            var = tester.snmpGet(oid);
            logger.info(oid + " = " + var);

            Thread.sleep(3 * 1000);
            logger.info("");
            logger.info("SNMP GetList");
            List<String> oidList = new ArrayList<String>();
            oidList.add(".1.3.6.1.2.1.1.1.0");
            oidList.add(".1.3.6.1.2.1.1.3.0");
            oidList.add(".1.3.6.1.2.1.1.5.0");

            List<VariableBinding> vblist = tester.snmpGet(oidList);
            for (VariableBinding vb : vblist) {
                logger.info("oid:" + vb.getOid() + ", var=" + vb.getVariable());
            }
        } catch (Exception e) {
            logger.error("Error:", e);
        } finally {
            tester.close();
        }
    }

    public void connect(String ip, int port, String community) throws Exception {
        String address = protocol + ":" + ip + "/" + port;
        // CommunityTarget target = SnmpUtil.createCommunityTarget(address,
        // community, version, 2 * 1000L, 3);

        target = new CommunityTarget();
        target.setCommunity(new OctetString(community));
        target.setAddress(GenericAddress.parse(address));
        target.setVersion(version);
        target.setTimeout(2 * 1000L); // milliseconds
        target.setRetries(3); // retry 3次

        try {
            udpTransportMapping = new DefaultUdpTransportMapping();
            // 這裡一定要呼叫 listen, 才能收到結果
            udpTransportMapping.listen();
            snmp = new Snmp(udpTransportMapping);

        } catch (Exception e) {
            logger.error("Error", e);
            throw e;
        }
    }

    public void close() {
        if (snmp != null) {
            try {
                snmp.close();
            } catch (IOException ex1) {
                snmp = null;
            }
        }
        if (udpTransportMapping != null) {
            try {
                udpTransportMapping.close();
            } catch (IOException ex2) {
                udpTransportMapping = null;
            }
        }
    }

    public Variable snmpGet(String oid) throws Exception {
        try {
            PDU pdu = new PDU();
            // pdu.add(new VariableBinding(new OID(new
            // int[]{1,3,6,1,2,1,1,2})));
            pdu.add(new VariableBinding(new OID(oid)));
            pdu.setType(PDU.GET);

            // 以同步的方式發送 snmp get, 會等待target 設定的 timeout 時間結束後
            // 就會以 Request time out 的方式 return 回來
            ResponseEvent response = snmp.send(pdu, target);
            // logger.debug("PeerAddress:" + response.getPeerAddress());
            PDU responsePdu = response.getResponse();

            if (responsePdu == null) {
                logger.debug("Request time out");
            } else {
                Vector<?> vbVect = responsePdu.getVariableBindings();
                logger.debug("vb size:" + vbVect.size());
                if (vbVect.size() == 0) {
                    logger.debug(" pdu vb size is 0 ");
                } else {
                    Object obj = vbVect.firstElement();
                    VariableBinding vb = (VariableBinding) obj;
                    // logger.debug(vb.getOid() + " = " + vb.getVariable());

                    // logger.info("success finish snmp get the oid!");
                    return vb.getVariable();
                }
            }

        } catch (Exception e) {
            logger.error("Error", e);
            throw e;
        }
        return null;
    }

    public List<VariableBinding> snmpGet(List<String> oidList) throws Exception {
        try {
            PDU pdu = new PDU();
            pdu.setType(PDU.GET);
            for (String oid : oidList) {
                pdu.add(new VariableBinding(new OID(oid)));
            }

            // 以同步的方式發送 snmp get, 會等待target 設定的 timeout 時間結束後
            // 就會以 Request time out 的方式 return 回來
            ResponseEvent response = snmp.send(pdu, target);
            // logger.debug("PeerAddress:" + response.getPeerAddress());
            PDU responsePdu = response.getResponse();

            if (responsePdu == null) {
                logger.debug("Request time out");
            } else {
                logger.debug(" response pdu vb size is " + responsePdu.size());
                List<VariableBinding> datalist = new ArrayList<VariableBinding>();
                for (int i = 0; i < responsePdu.size(); i++) {
                    VariableBinding vb = responsePdu.get(i);
                    // logger.debug(vb.getOid() + "=" + vb.getVariable());
                    datalist.add(vb);
                }
                return datalist;
            }

        } catch (Exception e) {
            logger.error("Error", e);
            throw e;
        }
        return null;
    }
}

執行結果

2014-12-04 17:19:11,055 [main] DEBUG SnmpGet 145
 vb size:1
2014-12-04 17:19:11,083 [main] INFO  SnmpGet 50
 .1.3.6.1.2.1.1.3.0 = 1 day, 1:13:23.16
2014-12-04 17:19:14,084 [main] INFO  SnmpGet 53

2014-12-04 17:19:14,085 [main] DEBUG SnmpGet 145
 vb size:1
2014-12-04 17:19:14,086 [main] INFO  SnmpGet 56
 .1.3.6.1.2.1.1.1.0 = Linux server.maxkit.com.tw 2.6.32-431.el6.i686 #1 SMP Fri Nov 22 00:26:36 UTC 2013 i686

SNMP walk

這是使用 GETNext 的方式,當有下一個OID 時,就自動往下抓取,直到沒有資料為止。

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.Null;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.Variable;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;

public class SnmpGet {
    public static Logger logger = LoggerFactory.getLogger(SnmpGet.class
            .getName());

    private static int version = SnmpConstants.version1;
    private static String protocol = "udp";

    private static CommunityTarget target = null;
    private static DefaultUdpTransportMapping udpTransportMapping = null;
    private static Snmp snmp = null;

    public static void main(String[] args) {

        String ip = "192.168.1.8";
        String community = "public";
        int port = 161;

        Variable var = null;
        SnmpGet tester = new SnmpGet();
        // tester.snmpGet(ip, port, community, oidval);
        try {
            tester.connect(ip, port, community);
            logger.info("");
            logger.info("SNMP walk");

            vblist = tester.snmpWalk("1.3.6.1.2.1.1");
            for (VariableBinding vb : vblist) {
                logger.info("oid:" + vb.getOid() + ", var=" + vb.getVariable());
            }
        } catch (Exception e) {
            logger.error("Error:", e);
        } finally {
            tester.close();
        }
    }

    public void connect(String ip, int port, String community) throws Exception {
        String address = protocol + ":" + ip + "/" + port;
        // CommunityTarget target = SnmpUtil.createCommunityTarget(address,
        // community, version, 2 * 1000L, 3);

        target = new CommunityTarget();
        target.setCommunity(new OctetString(community));
        target.setAddress(GenericAddress.parse(address));
        target.setVersion(version);
        target.setTimeout(2 * 1000L); // milliseconds
        target.setRetries(3); // retry 3次

        try {
            udpTransportMapping = new DefaultUdpTransportMapping();
            // 這裡一定要呼叫 listen, 才能收到結果
            udpTransportMapping.listen();
            snmp = new Snmp(udpTransportMapping);

        } catch (Exception e) {
            logger.error("Error", e);
            throw e;
        }
    }

    public void close() {
        if (snmp != null) {
            try {
                snmp.close();
            } catch (IOException ex1) {
                snmp = null;
            }
        }
        if (udpTransportMapping != null) {
            try {
                udpTransportMapping.close();
            } catch (IOException ex2) {
                udpTransportMapping = null;
            }
        }
    }

    /**
     * 1)responsePDU == null<br>
     * 2)responsePDU.getErrorStatus() != 0<br>
     * 3)responsePDU.get(0).getOid() == null<br>
     * 4)responsePDU.get(0).getOid().size() < targetOID.size()<br>
     * 5)targetOID.leftMostCompare(targetOID.size(),responsePDU.get(0).getOid())
     * !=0<br>
     * 6)Null.isExceptionSyntax(responsePDU.get(0).getVariable().getSyntax())<br>
     * 7)responsePDU.get(0).getOid().compareTo(targetOID) <= 0<br>
     */
    public List<VariableBinding> snmpWalk(String targetOid) {
        OID targetOID = new OID(targetOid);

        PDU requestPDU = new PDU();
        requestPDU.setType(PDU.GETNEXT);
        requestPDU.add(new VariableBinding(targetOID));

        try {
            List<VariableBinding> vblist = new ArrayList<VariableBinding>();
            boolean finished = false;
            while (!finished) {
                VariableBinding vb = null;
                ResponseEvent response = snmp.send(requestPDU, target);
                PDU responsePDU = response.getResponse();

                if (null == responsePDU) {
                    logger.debug("responsePDU == null");
                    finished = true;
                    break;
                } else {
                    vb = responsePDU.get(0);
                }
                // check finish
                finished = checkWalkFinished(targetOID, responsePDU, vb);
                if (!finished) {
                    // logger.debug("vb:" + vb.toString());
                    vblist.add(vb);
                    // Set up the variable binding for the next entry.
                    requestPDU.setRequestID(new Integer32(0));
                    requestPDU.set(0, vb);
                }
            }
            // logger.debug("success finish snmp walk!");
            return vblist;
        } catch (Exception e) {
            logger.error("Error: ", e);
        }
        return null;
    }

    /**
     * check snmp walk finish
     * 
     * @param resquestPDU
     * @param targetOID
     * @param responsePDU
     * @param vb
     * @return
     */
    private boolean checkWalkFinished(OID targetOID, PDU responsePDU,
            VariableBinding vb) {
        boolean finished = false;
        if (responsePDU.getErrorStatus() != 0) {
            logger.debug("responsePDU.getErrorStatus() != 0 ");
            logger.debug(responsePDU.getErrorStatusText());
            finished = true;
        } else if (vb.getOid() == null) {
            logger.debug("vb.getOid() == null");
            finished = true;
        } else if (vb.getOid().size() < targetOID.size()) {
            logger.debug("vb.getOid().size() < targetOID.size()");
            finished = true;
        } else if (targetOID.leftMostCompare(targetOID.size(), vb.getOid()) != 0) {
            logger.debug("targetOID.leftMostCompare() != 0");
            finished = true;
        } else if (Null.isExceptionSyntax(vb.getVariable().getSyntax())) {
            logger.debug("Null.isExceptionSyntax(vb.getVariable().getSyntax())");
            finished = true;
        } else if (vb.getOid().compareTo(targetOID) <= 0) {
            logger.debug("Variable received is not "
                    + "lexicographic successor of requested " + "one:");
            logger.debug(vb.toString() + " <= " + targetOID);
            finished = true;
        }
        return finished;

    }
}

測試結果

2014-12-04 17:19:17,087 [main] INFO  SnmpGet 60
 SNMP GetList
2014-12-04 17:19:17,091 [main] DEBUG SnmpGet 182
  response pdu vb size is 3
2014-12-04 17:19:17,091 [main] INFO  SnmpGet 68
 oid:1.3.6.1.2.1.1.1.0, var=Linux server.maxkit.com.tw 2.6.32-431.el6.i686 #1 SMP Fri Nov 22 00:26:36 UTC 2013 i686
2014-12-04 17:19:17,092 [main] INFO  SnmpGet 68
 oid:1.3.6.1.2.1.1.3.0, var=1 day, 1:13:29.25
2014-12-04 17:19:17,092 [main] INFO  SnmpGet 68
 oid:1.3.6.1.2.1.1.5.0, var=server.maxkit.com.tw
2014-12-04 17:19:20,092 [main] INFO  SnmpGet 72

2014-12-04 17:19:20,093 [main] INFO  SnmpGet 73
 SNMP walk
2014-12-04 17:19:20,130 [main] DEBUG SnmpGet 276
 targetOID.leftMostCompare() != 0
2014-12-04 17:19:20,130 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.1.0, var=Linux server.maxkit.com.tw 2.6.32-431.el6.i686 #1 SMP Fri Nov 22 00:26:36 UTC 2013 i686
2014-12-04 17:19:20,130 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.2.0, var=1.3.6.1.4.1.8072.3.2.10
2014-12-04 17:19:20,131 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.3.0, var=1 day, 1:13:32.26
2014-12-04 17:19:20,131 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.4.0, var=Root <root@localhost> (configure /etc/snmp/snmp.local.conf)
2014-12-04 17:19:20,131 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.5.0, var=server.maxkit.com.tw
2014-12-04 17:19:20,132 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.6.0, var=Unknown (edit /etc/snmp/snmpd.conf)
2014-12-04 17:19:20,132 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.8.0, var=0:00:00.01
2014-12-04 17:19:20,132 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.2.1, var=1.3.6.1.6.3.11.2.3.1.1
2014-12-04 17:19:20,132 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.2.2, var=1.3.6.1.6.3.15.2.1.1
2014-12-04 17:19:20,133 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.2.3, var=1.3.6.1.6.3.10.3.1.1
2014-12-04 17:19:20,133 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.2.4, var=1.3.6.1.6.3.1
2014-12-04 17:19:20,133 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.2.5, var=1.3.6.1.2.1.49
2014-12-04 17:19:20,133 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.2.6, var=1.3.6.1.2.1.4
2014-12-04 17:19:20,133 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.2.7, var=1.3.6.1.2.1.50
2014-12-04 17:19:20,133 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.2.8, var=1.3.6.1.6.3.16.2.2.1
2014-12-04 17:19:20,133 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.3.1, var=The MIB for Message Processing and Dispatching.
2014-12-04 17:19:20,134 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.3.2, var=The MIB for Message Processing and Dispatching.
2014-12-04 17:19:20,134 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.3.3, var=The SNMP Management Architecture MIB.
2014-12-04 17:19:20,134 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.3.4, var=The MIB module for SNMPv2 entities
2014-12-04 17:19:20,134 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.3.5, var=The MIB module for managing TCP implementations
2014-12-04 17:19:20,134 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.3.6, var=The MIB module for managing IP and ICMP implementations
2014-12-04 17:19:20,134 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.3.7, var=The MIB module for managing UDP implementations
2014-12-04 17:19:20,134 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.3.8, var=View-based Access Control Model for SNMP.
2014-12-04 17:19:20,135 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.4.1, var=0:00:00.01
2014-12-04 17:19:20,136 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.4.2, var=0:00:00.01
2014-12-04 17:19:20,137 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.4.3, var=0:00:00.01
2014-12-04 17:19:20,138 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.4.4, var=0:00:00.01
2014-12-04 17:19:20,139 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.4.5, var=0:00:00.01
2014-12-04 17:19:20,143 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.4.6, var=0:00:00.01
2014-12-04 17:19:20,143 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.4.7, var=0:00:00.01
2014-12-04 17:19:20,144 [main] INFO  SnmpGet 77
 oid:1.3.6.1.2.1.1.9.1.4.8, var=0:00:00.01

SNMP Asynchronous Get

如果在程式中,無法在發送 snmp request 之後,直接等待結果,例如在 UI 界面上發送 request,但 UI 無法被 blocking 以等待 response 或 timeout 的狀況下,我們就必須要使用非同步 SNMP Get。

程式中主要是利用 ThreadPool,以 multithread 的方式,在背景中發送 request,並以 event listener 作為 call back function。

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snmp4j.CommunityTarget;
import org.snmp4j.MessageDispatcherImpl;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;
import org.snmp4j.util.WorkerPool;

public class SnmpClientAsync {
    public static Logger logger = LoggerFactory.getLogger(SnmpClientAsync.class
            .getName());

    private static int version = SnmpConstants.version1;
    private static String protocol = "udp";

    private static CommunityTarget target = null;
    private static DefaultUdpTransportMapping udpTransportMapping = null;
    private static Snmp snmp = null;
    private WorkerPool threadPool = null;

    public static void main(String[] args) {

        String ip = "192.168.1.8";
        String community = "public";
        int port = 161;

        SnmpClientAsync tester = new SnmpClientAsync();
        try {
            tester.connect(ip, port, community);
            logger.info("");
            logger.info("SNMP GetList");
            List<String> oidList = new ArrayList<String>();
            oidList.add(".1.3.6.1.2.1.1.1.0");
            oidList.add(".1.3.6.1.2.1.1.3.0");
            oidList.add(".1.3.6.1.2.1.1.5.0");

            tester.snmpGet(oidList);

            // 非同步,必須等待一段處理時間
            Thread.sleep(3*1000);
        } catch (Exception e) {
            logger.error("Error:", e);
        } finally {
            tester.close();
        }
    }

    public void connect(String ip, int port, String community) throws Exception {
        String address = protocol + ":" + ip + "/" + port;

        target = new CommunityTarget();
        target.setCommunity(new OctetString(community));
        target.setAddress(GenericAddress.parse(address));
        target.setVersion(version);
        target.setTimeout(2 * 1000L); // milliseconds
        target.setRetries(3); // retry 3次

        try {
            threadPool = ThreadPool.create(ip + "SNMPWorkPool", 2);
            MultiThreadedMessageDispatcher dispatcher = new MultiThreadedMessageDispatcher(
                    threadPool, new MessageDispatcherImpl());

            udpTransportMapping = new DefaultUdpTransportMapping();

            snmp = new Snmp(dispatcher, udpTransportMapping);
            snmp.getMessageDispatcher().addMessageProcessingModel(new MPv1());
            snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c());
            snmp.getMessageDispatcher().addMessageProcessingModel(new MPv3());
            snmp.listen();
        } catch (Exception e) {
            logger.error("Error", e);
            throw e;
        }
    }

    public void close() {
        if (snmp != null) {
            try {
                snmp.close();
            } catch (IOException ex1) {
                snmp = null;
            }
        }
        if (udpTransportMapping != null) {
            try {
                udpTransportMapping.close();
            } catch (IOException ex2) {
                udpTransportMapping = null;
            }
        }
        if (threadPool != null) {
            threadPool.stop();
            threadPool = null;
        }
    }

    public void snmpGet(List<String> oidList) throws Exception {
        try {
            PDU pdu = new PDU();
            pdu.setType(PDU.GET);
            for (String oid : oidList) {
                pdu.add(new VariableBinding(new OID(oid)));
            }

            snmp.send(pdu, target, null, listener);
        } catch (Exception e) {
            logger.error("Error", e);
            throw e;
        }
    }

    public void printResponse(List<VariableBinding> datalist) {
        for (VariableBinding vb : datalist) {
            logger.info("oid:" + vb.getOid() + ", var=" + vb.getVariable());
        }
    }

    ResponseListener listener = new ResponseListener() {
        public void onResponse(ResponseEvent event) {
            ((Snmp) event.getSource()).cancel(event.getRequest(), this);
            PDU response = event.getResponse();
            PDU request = event.getRequest();
            //logger.debug("[request]:" + request);

            if (response == null) {
                logger.debug("[ERROR]: response is null");
            } else if (response.getErrorStatus() != 0) {
                logger.debug("[ERROR]: response status"
                        + response.getErrorStatus() + " Text:"
                        + response.getErrorStatusText());
            } else {
                logger.debug("Received response Success!!!");
                List<VariableBinding> datalist = new ArrayList<VariableBinding>();
                for (int i = 0; i < response.size(); i++) {
                    VariableBinding vb = response.get(i);
                    logger.debug(vb.toString());
                    datalist.add(vb);
                }
                printResponse(datalist);
            }
        }
    };

}

測試結果

2014-12-08 10:18:07,548 [main] INFO  SnmpClientAsync 49

2014-12-08 10:18:07,581 [main] INFO  SnmpClientAsync 50
 SNMP GetList
2014-12-08 10:18:07,607 [192.168.1.8SNMPWorkPool.0] DEBUG SnmpClientAsync 151
 Received response Success!!!
2014-12-08 10:18:07,607 [192.168.1.8SNMPWorkPool.0] DEBUG SnmpClientAsync 155
 1.3.6.1.2.1.1.1.0 = Linux koko.maxkit.com.tw 2.6.32-431.el6.i686 #1 SMP Fri Nov 22 00:26:36 UTC 2013 i686
2014-12-08 10:18:07,610 [192.168.1.8SNMPWorkPool.0] DEBUG SnmpClientAsync 155
 1.3.6.1.2.1.1.3.0 = 4 days, 18:12:20.49
2014-12-08 10:18:07,611 [192.168.1.8SNMPWorkPool.0] DEBUG SnmpClientAsync 155
 1.3.6.1.2.1.1.5.0 = koko.maxkit.com.tw
2014-12-08 10:18:07,611 [192.168.1.8SNMPWorkPool.0] INFO  SnmpClientAsync 133
 oid:1.3.6.1.2.1.1.1.0, var=Linux koko.maxkit.com.tw 2.6.32-431.el6.i686 #1 SMP Fri Nov 22 00:26:36 UTC 2013 i686
2014-12-08 10:18:07,611 [192.168.1.8SNMPWorkPool.0] INFO  SnmpClientAsync 133
 oid:1.3.6.1.2.1.1.3.0, var=4 days, 18:12:20.49
2014-12-08 10:18:07,612 [192.168.1.8SNMPWorkPool.0] INFO  SnmpClientAsync 133
 oid:1.3.6.1.2.1.1.5.0, var=koko.maxkit.com.tw

Reference

Java實現snmp的get和walk代碼示例

Introduction to snmp4j