73

基于LLDP和OpenFlow的网络拓扑检测

 5 years ago
source link: https://www.sdnlab.com/21008.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

作者简介:周正强,北京邮电大学未来网络实验室在读研究生,个人邮箱:[email protected]

网络拓扑检测对于网络策略的执行十分重要,本题主要考察对拓扑检测原理的理解以及对全局拓扑的检测。

LLDP-Openflow-668x400.jpg

一 实验目的

1.掌握网络拓扑检测相关原理
2.熟悉SDN网络中拓扑发现机制
3.掌握控制器集群原理

二 实验原理

在SDN网络中拓扑检测是相当重要的,LLDP以及其他拓扑检测协议广泛应用于网络拓扑检测中,通过本实验掌握其检测原理,了解其原理实现过程。同时针对SDN网络中通过openflow协议将底层网络交由控制器处理,可以通过控制器集群操作实现,控制器可以彼此分享各自的运行状态,当底层Openflow交换机连接多个控制器时,由交换机确定主备控制器,这对于容错和高可用性是非常有用的。

三 实验任务

1.搭建下图中所示环境,给出控制器web界面拓扑截图,并分析上述环境中采用的控制器网络拓扑检测原理。

LLDP-Openflow-1.png

2.在上述网络环境中,给出一种全局拓扑检测方案,用简洁的流程图描述检测拓扑的过程。

四 实验步骤

4.1 实验环境

采用的环境如下所述:

  • Ubuntu14.04LTS虚机中安装2.2.1版本的mininet网络仿真软件(IP地址为192.168.88.136)
  • 2台ubuntu16.04LTS虚机分别安装ONOS1.10.13版本的控制器(IP地址分别为controller 1: 192.168.88.128、controller 2: 192.168.88.139)

采用mininet网络仿真软件实现底层网络拓扑,在脚本中指定其控制器等。同时由于题中需要使用两台控制器,因此我们采取两台虚机分别搭建ONOS1.10.13版本的方案。在两台虚机中分别开启控制器,利用python脚本设置拓扑连接对应的控制器,完成上述环境的搭建。同时,鉴于题中使用两台控制器,所以借用ONOS中的onos-form-cluster脚本实现ONOS控制器的分布式集群,可以使得发生事件被分布式存储与集群中的所有节点共享。同时,我们也可以在集群状态中点击各个控制器查看各个控制器下的WEB界面拓扑。

4.2 实验步骤操作

1)首先我们需要开启两台ONOS控制器,不过本题采用的是ONOS源码编译完成后生成的onos.tar.gz部署开启onos,和基础题中的开启方法有所区别,具体的步骤如后文所述。
2)在两台虚拟机中生成ssh密钥,将密钥拷贝到两台虚机中,实现两个虚机的免密访问,具体操作百度即可(最常用的命令为ssh-keygen和ssh-copy-id)。
3)在onos源代码编译完成后会在buck-out文件夹中生成一个onos.tar.gz,将此文件夹拷贝到home目录下,并解压到/tmp目录下,如下图中所示:

LLDP-Openflow-2.png

onos.tar.gz解压

4)在该压缩包解压完成后,执行/tmp/onos-1.10.5-SNAPSHOT/apache-karaf-3.0.8/bin/start即可开启控制器。

LLDP-Openflow-5.png

onos开启命令

5)执行/tmp/onos-1.10.5-SNAPSHOT/apache-karaf-3.0.8/bin/client命令即可登入ONOS的经典karaf界面。

LLDP-Openflow-3.png

登录onos的karaf界面

6)在另一台ONOS控制器的虚机中重复操作3~5,完成两台ONOS控制器的开启工作。
7)分别在两台控制器中激活的基本app模块(否则之后mininet创建的ovs交换机无法连接到控制器),如下图中所示:

LLDP-Openflow-4.png

激活对应的app模块

8)在mininet虚机中根据题中拓扑创建对应的脚本文件:

Java
1.#!/usr/bin/env python   2.# coding=utf-8   3.from mininet.net import Mininet   4.from mininet.node import RemoteController   5.from mininet.node import Host   6.from mininet.node import OVSSwitch   7.from mininet.cli import CLI   8.from mininet.log import setLogLevel, info   9.#from mininet.link import TCLink, Intf   10.#from subprocess import call   11.   12.def myNetwork():   13.    #创建一个mininet网络,其中build表示是否立即从topo构建网络,默认为True   14.    #ipBase表示设置网络的ip地址段   15.    net = Mininet(topo=None, build=False, ipBase='10.0.0.0/8')   16.    #显示通知   17.    info('*****Adding Controller*****\n')   18.    #设定远程控制器的信息,使用TCP模式连接   19.    c0 = net.addController(name='c0',controller=RemoteController, ip='192.168.88.128', port=6653, protocol='tcp')   20.    #指定第二个控制器   21.    c1 = net.addController(name='c1',controller=RemoteController, ip='192.168.88.139', port=6653, protocol='tcp')   22.   23.    #添加交换机   24.    info('*****Adding Switches*****\n')   25.    s1 = net.addSwitch('s1', cls=OVSSwitch, dpid='1')   26.    s2 = net.addSwitch('s2', cls=OVSSwitch, dpid='2')   27.    s3 = net.addSwitch('s3', cls=OVSSwitch, dpid='3')   28.    s4 = net.addSwitch('s4', cls=OVSSwitch, dpid='4')   29.    s5 = net.addSwitch('s5', cls=OVSSwitch, dpid='5')   30.    s6 = net.addSwitch('s6', cls=OVSSwitch, dpid='6')   31.    s7 = net.addSwitch('s7', cls=OVSSwitch, dpid='7')   32.   33.    #添加主机   34.    info('*****Adding Hosts*****\n')   35.    h1 = net.addHost('h1', cls=Host, ip='10.0.0.1', mac="00:00:00:00:00:01", defaultRoute=None)   36.    h2 = net.addHost('h2', cls=Host, ip='10.0.0.2', mac="00:00:00:00:00:02", defaultRoute=None)   37.    h3 = net.addHost('h3', cls=Host, ip='10.0.0.3', mac="00:00:00:00:00:03", defaultRoute=None)   38.   39.    #连接拓扑   40.    info('*****Adding Links*****\n')   41.    net.addLink(s1, s2, 2, 1)   42.    net.addLink(s2, s3, 2, 1)   43.    net.addLink(s3, s4, 2, 1)   44.    net.addLink(s4, s5, 2, 1)   45.    net.addLink(s5, s6, 2, 2)   46.    net.addLink(s5, s7, 3, 2)   47.    net.addLink(h1, s1, 1, 1)   48.    net.addLink(h2, s7, 1, 1)   49.    net.addLink(h3, s6, 1, 1)   50.   51.    #构建网络   52.    info('*****Starting Network*****\n')   53.    net.build()   54.    info('*****Starting Controllers*****\n')   55.    for controller in net.controllers:   56.        controller.start()   57.       58.    #开启交换机   59.    info('*****Starting Switches*****\n')   60.    net.get('s1').start([c0])   61.    net.get('s2').start([c0])   62.    net.get('s3').start([c0])   63.    net.get('s4').start([c1])   64.    net.get('s5').start([c1])   65.    net.get('s6').start([c1])   66.    net.get('s7').start([c1])   67.   68.    CLI(net)   69.    net.stop()   70.   71.if __name__ == '__main__':   72.    setLogLevel('info')   73. myNetwork()  
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
1.#!/usr/bin/env python  
2.# coding=utf-8  
3.from mininet.net import Mininet  
4.from mininet.node import RemoteController  
5.from mininet.node import Host  
6.from mininet.node import OVSSwitch  
7.from mininet.cli import CLI  
8.from mininet.log import setLogLevel, info  
9.#from mininet.link import TCLink, Intf  
10.#from subprocess import call  
11.  
12.def myNetwork():  
13.    #创建一个mininet网络,其中build表示是否立即从topo构建网络,默认为True  
14.    #ipBase表示设置网络的ip地址段  
15.    net = Mininet(topo=None, build=False, ipBase='10.0.0.0/8')  
16.    #显示通知  
17.    info('*****Adding Controller*****\n')  
18.    #设定远程控制器的信息,使用TCP模式连接  
19.    c0 = net.addController(name='c0',controller=RemoteController, ip='192.168.88.128', port=6653, protocol='tcp')  
20.    #指定第二个控制器  
21.    c1 = net.addController(name='c1',controller=RemoteController, ip='192.168.88.139', port=6653, protocol='tcp')  
22.  
23.    #添加交换机  
24.    info('*****Adding Switches*****\n')  
25.    s1 = net.addSwitch('s1', cls=OVSSwitch, dpid='1')  
26.    s2 = net.addSwitch('s2', cls=OVSSwitch, dpid='2')  
27.    s3 = net.addSwitch('s3', cls=OVSSwitch, dpid='3')  
28.    s4 = net.addSwitch('s4', cls=OVSSwitch, dpid='4')  
29.    s5 = net.addSwitch('s5', cls=OVSSwitch, dpid='5')  
30.    s6 = net.addSwitch('s6', cls=OVSSwitch, dpid='6')  
31.    s7 = net.addSwitch('s7', cls=OVSSwitch, dpid='7')  
32.  
33.    #添加主机  
34.    info('*****Adding Hosts*****\n')  
35.    h1 = net.addHost('h1', cls=Host, ip='10.0.0.1', mac="00:00:00:00:00:01", defaultRoute=None)  
36.    h2 = net.addHost('h2', cls=Host, ip='10.0.0.2', mac="00:00:00:00:00:02", defaultRoute=None)  
37.    h3 = net.addHost('h3', cls=Host, ip='10.0.0.3', mac="00:00:00:00:00:03", defaultRoute=None)  
38.  
39.    #连接拓扑  
40.    info('*****Adding Links*****\n')  
41.    net.addLink(s1, s2, 2, 1)  
42.    net.addLink(s2, s3, 2, 1)  
43.    net.addLink(s3, s4, 2, 1)  
44.    net.addLink(s4, s5, 2, 1)  
45.    net.addLink(s5, s6, 2, 2)  
46.    net.addLink(s5, s7, 3, 2)  
47.    net.addLink(h1, s1, 1, 1)  
48.    net.addLink(h2, s7, 1, 1)  
49.    net.addLink(h3, s6, 1, 1)  
50.  
51.    #构建网络  
52.    info('*****Starting Network*****\n')  
53.    net.build()  
54.    info('*****Starting Controllers*****\n')  
55.    for controller in net.controllers:  
56.        controller.start()  
57.      
58.    #开启交换机  
59.    info('*****Starting Switches*****\n')  
60.    net.get('s1').start([c0])  
61.    net.get('s2').start([c0])  
62.    net.get('s3').start([c0])  
63.    net.get('s4').start([c1])  
64.    net.get('s5').start([c1])  
65.    net.get('s6').start([c1])  
66.    net.get('s7').start([c1])  
67.  
68.    CLI(net)  
69.    net.stop()  
70.  
71.if __name__ == '__main__':  
72.    setLogLevel('info')  
73.     myNetwork()  

9)执行脚本文件使其连接两个控制器,如下图中所示:

LLDP-Openflow-6.png

Mininet脚本执行

10)进行pingall操作则可以使得控制器一侧通过对应的协议获取到主机信息,得到底层网络的完整拓扑信息。

LLDP-Openflow-7.png

pingall操作

11)完成后则可以在控制器的UI界面获取相应的拓扑并进行分析。

4.3 实验拓扑图

各控制器web界面拓扑截图
1)打开controller 1的web界面192.168.88.128:8181/onos/ui/index.html,可得到如下网络拓扑。

LLDP-Openflow-8.png

controller 1拓扑图

2)打开controller 2的web界面192.168.88.139:8181/onos/ui/index.html,可得到如下网络拓扑。

LLDP-Openflow-9.png

controller 2拓扑图

采用ONOS集群的web界面拓扑截图
1)在实验步骤的第六步之后可以开启集群脚本。在Controller 1中执行onos-form-cluster脚本,实现两个控制器的集群,我们在IP地址为192.168.88.128的机器中执行脚本命令/tmp/onos-1.10.5-SNAPSHOT/bin/onos-form-cluster 192.168.88.128 192.168.88.139,如下图中所示:

LLDP-Openflow-10.png

执行onos集群脚本

2)首先打开192.168.88.128:8181/onos/ui/index.html界面,可以查看到此时的控制器拓扑,其中深蓝色为连接192.168.88.128控制器的交换机,淡蓝色为连接192.168.88.139控制器的交换机,如下图中所示:

LLDP-Openflow-11.png

集群后控制器拓扑

五 拓扑检测原理

5.1 网络拓扑检测原理

在本网络环境采用的ONOS控制器,其网络拓扑检测分为三部分:链路发现、交换机发现、主机发现。

交换机发现:使用的OPENFLOW协议。具体过程主要分为三个阶段:控制器启动监听6633端口、交换机与控制器建立连接、控制器与交换机版本协商。首先,打开控制器,启动OpenFlowAgent,监听端口,等待交换机建立连接;接着,使用OpenFlow PipelineFactory,新建channel使交换机与控制器建立连接,等待交换机发送hello消息;最后,控制器收到OPENFLOW Hello的消息,便会调用processOFHello方法进行版本协商,如果协商失败,控制器则会主动断开连接,如果协商成功,则连接成功。

以下主要阐述链路发现原理和主机发现原理。

5.1.1 链路发现原理
链路发现主要应用的是LLDP和BDDP协议(仅在有非OF交换机时),首先阐述这两个协议的链路发现原理,再从控制器层面分析对应的网络拓扑检测方法。

LLDP链路发现原理
LLDP用于检测两个OF交换机是否直连,其检测原理如下图中所示:

1)控制器首先向switch1下发packet_out消息,即是一个LLDP包,此时switch1将这个包从指定的的端口转发出去,此时别的交换机switch2收到该LLDP封包时,会通过PACKET_IN消息上报给控制器,这个时候控制器就可以知道switch1和switch2是相连的,完成一次链路发现检测。
2)如果PACKET_OUT的LLDP包并未PACKET_IN给控制器,则会下发BDDP包或者判定端口和主机相连,见后文分析。
3)LLDP包只有一跳存活时间的特性,也即是只存在于两个相邻的交换机中。

LLDP-Openflow-12.png

LLDP检测原理图

BDDP检测原理(监测网络中非OF交换机)
BDDP用于检测OF交换机互联中是否存在非OF交换机,通过下图进行分析阐述:

1)首先在SDN控制器中会优先通过PACKET_OUT消息下发LLDP包给switch1,此时OF1会根据指定的LLDP包中指定的端口将封包转发出去,此时经过的非OF交换机,则该LLDP包会被丢弃,控制器无法收到这个包的PACKET_IN消息。
2)然后,控制器会给switch1通过PACKET_OUT消息下发一个BDDP包,此时通过switch1对应的端口转发出去后,通过非OF交换机转发后会在switch2通过PACKET_IN消息上传给控制器,此时控制器可以判定在switch1和switch2之间存在着非OF交换机。
3)此外,还存在一种情况为LLDP封包丢失,BDDP包也并没有PACKET_IN上报给控制器,此时则可以判定switch1的2端口连接的是一个主机,并没有连接交换机。

LLDP-Openflow-13.png

BDDP检测原理

5.1.2 ARP检测原理(主机发现)
在SDN中有一项很重要的检测原理是ARP请求,用于节点IP地址解析其MAC地址,然后进行局域网内部通信。其解析过程如下:

1)H1 ping H2时,即10.0.0.1 ping 10.0.0.2,此时没有H2的MAC,因此需做一次ARP解析,此时ARP请求会被switch1以packet_in消息的形式上报给controller;
2)Controller收到ARP请求后会记录H1的位置,并且向同一网段中所有的交换机请求H2的位置,以泛洪的形式packet_out给所有的交换机;
3)所有的交换机收到请求后悔检查是否存在该主机,此时只有switch2会以packet_in的形式给controller一个ARP回复;
4)Controller收到switch2的回复时会记录H2的位置,并将ARP回复以packet_out消息发送给switch1,此时switch1再发送给H1主机。
5)ARP请求完成后再开始传输ICMP请求报文。事实上ARP请求在网络拓扑中也是属于发现主机的一种方式,通过LLDP和BDDP可以发现交换机的拓扑关系,但是主机记录并不完善,需要ARP请求将整个网络拓扑请求完善。

LLDP-Openflow-14.png

ARP请求解析原理

5.2 全局拓扑检测方案

在上述网络环境中有两个控制器,我们将一个控制器直连和管控的网络称为一个集群(cluster),所以本题中有两个独立的控制平面相邻的集群。在通常情况下,控制器不能发现其他集群网络的设备和链路,所以需要不同集群的控制器进行拓扑信息的交互,来解决全局拓扑的检测问题。

本方案的主要思路是首先使用指纹信息(fingerprint)来标注设备和链路是属于哪一个集群。然后各控制器使用LLDP协议进行拓扑发现,并将连接两个集群之间的链路标记为边缘链路。最后各控制器间交换本集群的拓扑信息,收到后匹配边缘链路将不同集群的拓扑连接成全局拓扑,并使用pinall发现所有主机。具体方案如下:
准备工作:打开ONOS,在Controller 1中执行onos-form-cluster脚本,实现两个控制器的集群,具体步骤见上文。

LLDP-Openflow-15.png

全局拓扑监测方案流程图

1.首先为每一个集群生成一个不重复的集群名称,由集群名称进行稳定散列编码可以得到一个指纹信息(fingerprint),指纹信息可以唯一代表这个集群;
2.进行LLDP探测,以探测与交换机3相连的链路为例,由控制器构造一个探针,其中需要将指纹信息编码到源mac地址(即交换机3的MAC地址)中,探针的其他内容与普通的LLDP一致;
3.控制器通过packet-out消息将探针下发给交换机3,交换机3收到将收到的消息发送到所有端口;
4.与交换机3相连的其他交换机收到来自3的探针,通过packet-in消息发送回控制器(这个控制器可能不是交换机3所属的控制器了,交换机2将收到的探针上报给控制器1,而交换机4上报给控制器2);
5.各控制器接收各交换机发上来的探针,并解析LLDP探针,并从源MAC地址中解析出源交换机所属集群的指纹信息,进行判断:

  • 5a.若指纹信息与本控制器的指纹信息一致,将此链路标记为本集群的链路;
  • 5b.若指纹信息与本控制器的指纹信息不一致,将此链路标记为边缘链路;

    6.重复步骤2、3、4、5,直至遍历完所有的交换机,此时每个控制器都储存有本集群的拓扑信息:本集群交换机,源端和目的端都在本集群的链路,边缘链路;
    7.控制器之间互相发送自己的拓扑信息,此时各控制器存储了自己和其他集群的拓扑信息;
    8.针对边缘链路,控制器通过匹配源MAC地址和目的MAC地址,将不同集群的拓扑进行连接,得到全局的交换机拓扑;
    9.进行pingall操作,通过arp协议发现网络中的所有主机,最终得出全局拓扑。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK