网络拓扑算法以及snmp4j简介

基本概念

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的定义与具体的网络管理协议无关

image.png

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。

  1. V1、V2C选项
    a) –c COMMUNITY 指定共同体字符串
  2. 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时才需要。

拓扑发现原理

PPT
20160430-NCC拓扑计算简介.pptx

算法应用举例
我们可以从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. 剔除判定:间接连接间的方向信息,不存在交集
    如果存在交集,说明这两个端口间还有别的设备,那么只能是间接连接,不会是直接连接

思路如下:
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不是直接连接。

图示如下:

image.png

拓扑算法
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);
    }
}

执行结果如下:

image.png

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容