基本概念
SNMP协议介绍
简单网络管理协议(SNMP:Simple Network Management Protocol)是由互联网工程任务组(IETF:Internet Engineering Task Force )定义的一套网络管理协议。该协议基于简单网关监视协议(SGMP:Simple Gateway Monitor Protocol)。利用SNMP,一个管理工作站可以远程管理所有支持这种协议的网络设备,包括监视网络状态、修改网络设备配置、接收网络事件警告等。虽然SNMP开始是面向基于IP的网络管理,但作为一个工业标准也被成功用于电话网络管理。
SNMP基本原理
SNMP采用了Client/Server模型的特殊形式:代理/管理站模型。对网络的管理与维护是通过管理工作站与SNMP代理间的交互工作完成的。每个SNMP从代理负责回答SNMP管理工作站(主代理)关于MIB定义信息的各种查询。
MIB
管理信息库(MIB,Management Information Base)是TCP/IP网络管理协议标准框架的内容之一,MIB定义了受管设备必须保存的数据项、允许对每个数据项进行的操作及其含义,即管理系统可访问的受管设备的控制和状态信息等数据变量都保存在MIB中。
MIB的定义与具体的网络管理协议无关
SNMP示例
snmpwalk -c broadapublic -v2c 10.1.1.51 .1.3.6.1.2.1.4.20
snmpwalk -c broadapublic -v2c 10.1.1.51
a) –h 显示帮助
b) –v 1|2c|3 指定SNMP协议版本
c) –V 显示当前SNMPWALK命令行版本
d) –r RETRIES 指定重试次数,默认为0次。
e) –t TIMEOUT 指定每次请求的等待超时时间,单为秒,默认为3秒。
f) –Cc 指定当在WALK时,如果发现OID负增长将是否继续WALK。
- V1、V2C选项
a) –c COMMUNITY 指定共同体字符串 - V3选项
a) –l LEVEL 指定安全级别:noAuthNoPriv|authNoPriv|authPriv
b) –u USER-NAME 安全名字
c) –a PROTOCOL 验证协议:MD5|SHA。如果-l指定为authNoPriv或authPriv时才需要。
d) –A PASSPHRASE 验证字符串。如果-l指定为authNoPriv或authPriv时才需要。
e) –x PROTOCOL 加密协议:DES。如果-l指定为authPriv时才需要。
f) –X PASSPHRASE 加密字符串:如果-l指定为authPriv时才需要。
算法应用举例
我们可以从FDB得知以下链路关系
P = Port 端口号 (后面第一个数字代表节点号,第二个代表端口号)
N = Node 节点号
后面的第一个字母表示
1、P11–>N3
2、P11-->N2
3、P31-->N1
4、P32-->N2
5、P22-->N3
6、P22–>N1
根据直接连接判断定理2,可以得知N1和N2之间是间接连接
- 剔除判定:间接连接间的方向信息,不存在交集
如果存在交集,说明这两个端口间还有别的设备,那么只能是间接连接,不会是直接连接
思路如下:
1、N1和N2有两条连接关系:
P11–>P22 / P22–>P11 (由P11-->N2和P22–>N1推理得到)
P22–>P32 / P11–>P31 (由P22-->N3、P32-->N2和P11–>N3、P31–>N1推理得知)
2、因为第二条线跟第一条线重合了,存在交集关系,所以根据剔除判定定律判断N1和N2不是直接连接。
图示如下:
拓扑算法
Topo算法思路
源码:git@git.uyunsoft.cn:chenbo1/topoAlgorithm.git
一、SNMP4J介绍
SNMP4J是一个用Java来实现SNMP(简单网络管理协议)协议的开源项目.它支持以命令行的形式进行管理与响应。SNMP4J是纯面向对象设计与SNMP++(用C++实现SNMPv1/v2c/v3)相类似。
SNMP4J API 提供以下下特性:
支持MD5和SHA验证,DES,3DES,AES128、AES192和AES256加密的SNMPv3。
支持MPv1,MPv2C和MPv3,带执行的可阻塞的信息处理模块。
全部PDU格式。
可阻塞的传输拓扑。支持UPD、TCP、TLS 。
可阻塞的超时模块。
同步和异步请求。
命令发生器以及命令应答器的支持。
基于Apache license的开源免费。
JAVA 1.4.1或更高版本(2.0或更高版本需要jdk1.6及以上的支持)。
基于LOG4J记录日志。
使用GETBULK实现Row-based的有效的异步表格获取。
支持多线程。
二、SNMP4J重要的类和接口介绍
2.1、Snmp类
Snmp类:该类是SNMP4J中最为核心的类。负责SNMP报文的接受和发送。它提供了发送和接收PDU的方法,所有的PDU类型都可以采用同步或者异步的方式被发送
2.2、PDU类和ScopedPDU类
该类是SNMP报文单元的抽象,其中PDU类适用于SNMPv1和SNMPv2c。ScopedPDU类继承于PDU类,适用于SNMPv3。
2.3、Target接口和CommunityTarget类以及UserTarget类
对应于SNMP代理的地址信息,包括IP地址和端口号(161)。其中Target接口适用于SNMPv1和SNMPv2c。CommunityTarget类实现了Target接口,用于SNMPv1和SNMPv2c这两个版本,UserTarget类实现了Target接口,适用于SNMPv3。
2.4、TransportMapping接口
该接口代表了SNMP4J所使用的传输层协议。这也是SNMP4J一大特色的地方。按照RFC的规定,SNMP是只使用UDP作为传输层协议的。而SNMP4J支持管理端和代理端使用UDP或者TCP进行传输。该接口有两个子接口。
2.5、Snmp、Target、PDU三者的关系
Target代表远程设备或者远程实体、PDU代表管理端同Target通信的数据,Snmp就代表管理者管理功能(其实就是数据的收发)的具体执行者。
打个比方:Target就是你远方的恋人,PDU就是你们之间传递的情书、而Snmp就是负责帮你寄信收信的邮差。
2.6、snmpwalk代码实践
snmp4j官网:http://www.snmp4j.org/
API Document:http://www.snmp4j.org/doc/index.html
代码地址:git@git.uyunsoft.cn:chenbo1/snmp.git
private static final int DEFAULT_VERSION = SnmpConstants.version2c;
private static final String DEFAULT_PROTOCOL = "udp";
private static final int DEFAULT_PORT = 161;
private static final long DEFAULT_TIMEOUT = 3 * 1000L;
private static final int DEFAULT_RETRY = 3;
private static final String OID_head = "1.3.6.1.2.1.17.4.3.1.";//OID头部
/**
* 创建对象communityTarget
*
* @param ip
* @param community
* @return CommunityTarget
*/
public static CommunityTarget createDefault(String ip, String community) {
//定义远程主机的地址
Address address = GenericAddress.parse(DEFAULT_PROTOCOL + ":" + ip + "/" + DEFAULT_PORT);
//设定CommunityTarget
CommunityTarget target = new CommunityTarget();
target.setCommunity(new OctetString(community));
//定义远程主机的地址
target.setAddress(address);
//设置使用的snmp版本
target.setVersion(DEFAULT_VERSION);
//设置超时的时间
target.setTimeout(DEFAULT_TIMEOUT); // milliseconds
//设置超时重试次数
target.setRetries(DEFAULT_RETRY);
return target;
}
/**
* 异步采集信息
*
* @param ip
* @param community
* @param group
* @param identifier
*/
public static void snmpAsynWalk(String ip, String community, final Map<String, FDB> group, int identifier) {
final CommunityTarget target = createDefault(ip, community);
Snmp snmp = null;
try {
//设定传输协议为UDP
DefaultUdpTransportMapping transport = new DefaultUdpTransportMapping();
//创建SNMP对象,用于发送请求PDU
snmp = new Snmp(transport);
snmp.listen();
//创建请求pdu,获取mib
final PDU pdu = new PDU();
//设置OID地址
final OID targetOID = new OID(OID_head+identifier);
final CountDownLatch latch = new CountDownLatch(1);
//调用的add方法绑定要查询的OID
pdu.add(new VariableBinding(targetOID));
//调用setType()方法来确定该pdu的类型
pdu.setType(PDU.GETBULK);
// static int GET Denotes a get PDU. 单个
// static int GETBULK Denotes a SNMPv2c/v3 getbulk PDU. 大数据量
// static int GETNEXT Denotes a getnext (search) PDU. 单个
//GETBULK操作会根据最大重试值执行一个连续的GETNEXT操作
//Sets the maximum repetitions of repeatable variable bindings in GETBULK requests.
pdu.setMaxRepetitions(Integer.MAX_VALUE);
//Sets the number of non repeater variable bindings in a GETBULK PDU.
pdu.setNonRepeaters(0);
ResponseListener listener = new ResponseListener() {
public void onResponse(ResponseEvent event) {
((Snmp) event.getSource()).cancel(event.getRequest(), this);
try {
PDU response = event.getResponse();
if (response == null) {
System.out.println("[ERROR]: response is null");
} else if (response.getErrorStatus() != 0) {
System.out.println("[ERROR]: response status" + response.getErrorStatus() + " Text:"
+ response.getErrorStatusText());
} else {
VariableBinding vb = response.get(0);
boolean finished = checkWalkFinished(targetOID, pdu, vb);
if (!finished) {
String s = vb.getOid().toString();
s = "*." + s.substring(23, s.length());
synchronized (group) {
if (targetOID.toString().equals("1.3.6.1.2.1.17.4.3.1.1")) {// Mac
if (group.containsKey(s)) {
group.get(s).setMac(vb.getVariable().toString());
} else {
FDB data = new FDB();
data.setMac(vb.getVariable().toString());
group.put(s, data);
}
} else {// Port
if (group.containsKey(s)) {
group.get(s).setPort(vb.getVariable().toString());
} else {
FDB data = new FDB();
data.setPort(vb.getVariable().toString());
group.put(s, data);
}
}
}
pdu.setRequestID(new Integer32(0));
pdu.set(0, vb);
((Snmp) event.getSource()).getNext(pdu, target, null, this);
} else {
latch.countDown();
}
}
} catch (Exception e) {
e.printStackTrace();
latch.countDown();
}
}
};
snmp.getNext(pdu, target, null, listener);
latch.await(30, TimeUnit.SECONDS);
snmp.close();
} catch (Exception e) {
e.printStackTrace();
System.out.println("SNMP Asyn Walk Exception:" + e);
}
}
执行结果如下:
BRIDGE-MIB
http://www.oidview.com/mibs/0/BRIDGE-MIB.html
转发表的OID:dot1dTpFdbTable(1.3.6.1.2.1.17.4.3)
相关资料
BRIDGE-MIB:http://www.oidview.com/mibs/0/BRIDGE-MIB.html
snmp学习总结—snmp4j介绍:http://www.cnblogs.com/xdp-gacl/p/4187089.html
snmp4j API Doc:http://www.snmp4j.org/doc/index.html
SNMP协议以及著名的MIB详解:https://my.oschina.net/barter/blog/124109