视频链接
建议把清晰度调到最高
队名
不想取名
本组成员
学号 | 姓名 | 工作分配 | 分工占比 |
---|---|---|---|
031702422 | 朱宏(组长) | 主要代码编写 | 26% |
031702419 | 姚彬锟 | 撰写博客,辅助代码(Debug)等 | 18% |
031702420 | 张庆焰 | 录制视频,辅助代码(Debug)等 | 18% |
031702425 | 吴永铭 | 查找资料,创建拓扑,上传视频等 | 18% |
041602630 | 张周伟 | 查阅资料,制作ppt和演讲 | 20% |
负载均衡代码如下
# -*- coding: utf-8 -*-
import httplib2
import time
import json
class OdlUtil:
url = ''
def __init__(self, host, port):
self.url = 'http://' + host + ':' + str(port)
def install_flow(self, container_name='default',username="admin", password="admin"):
http = httplib2.Http()
http.add_credentials(username, password)
headers = {'Accept': 'application/json'}
flow_name = 'flow_' + str(int(time.time()*1000))
#s3流表
#在检测h4发包的时候s3的1口流量空闲时发的流表
h4_to_s3_1 ='{"flow": [{"id": "0","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.4/32","ipv4-destination": "10.0.0.1/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "1"},"order": "0"}]}}]},'
'"priority": "101","cookie": "1","table_id": "0"}]}'
#在检测h5发包的时候s3的1口流量空闲时发的流表
h5_to_s3_1 ='{"flow": [{"id": "1","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.5/32","ipv4-destination": "10.0.0.1/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "1"},"order": "0"}]}}]},'
'"priority": "101","cookie": "1","table_id": "0"}]}'
mh5_to_s3_1 ='{"flow": [{"id": "1","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.5/32","ipv4-destination": "10.0.0.1/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "1"},"order": "0"}]}}]},'
'"priority": "100","cookie": "1","table_id": "0"}]}'
#在检测h5发包的时候s3的1口流量满载时发的流表
h5_to_s3_2 ='{"flow": [{"id": "2","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.5/32","ipv4-destination": "10.0.0.1/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "2"},"order": "0"}]}}]},'
'"priority": "101","cookie": "1","table_id": "0"}]}'
mh5_to_s3_2 ='{"flow": [{"id": "2","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.5/32","ipv4-destination": "10.0.0.1/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "2"},"order": "0"}]}}]},'
'"priority": "100","cookie": "1","table_id": "0"}]}'
#s2流表
s2_1='{"flow": [{"id": "0","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.5/32","ipv4-destination": "10.0.0.1/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "1"},"order": "0"}]}}]},'
'"priority": "101","cookie": "1","table_id": "0"}]}'
#s1流表
s1_4To1='{"flow": [{"id": "0","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.4/32","ipv4-destination": "10.0.0.1/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "4"},"order": "0"}]}}]},'
'"priority": "101","cookie": "1","table_id": "0"}]}'
s1_5To1='{"flow": [{"id": "1","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.5/32","ipv4-destination": "10.0.0.1/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "4"},"order": "0"}]}}]},'
'"priority": "101","cookie": "1","table_id": "0"}]}'
headers = {'Content-type': 'application/json'}
num=0
#下发流表,中间的地址可以从ODL控制器页面获得
#先把s1和s2的流表都下了
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/flow/0', body=s1_4To1, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/flow/1', body=s1_5To1, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:2/flow-node-inventory:table/0/flow/0', body=s2_1, method='PUT',headers=headers)
#s3调用h5到1的流表
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:3/flow-node-inventory:table/0/flow/0', body=h5_to_s3_1, method='PUT',headers=headers)
while num < 4 :
#获取s3端口1的流量
uri = 'http://127.0.0.1:8181/restconf/operational/opendaylight-inventory:nodes/node/openflow:3/node-connector/openflow:3:1'
response, content = http.request(uri=uri, method='GET')
content = json.loads(content.decode('utf-8'))
statistics = content['node-connector'][0]['opendaylight-port-statistics:flow-capable-node-connector-statistics']
bytes1 = statistics['bytes']['transmitted']
#1秒后再次获取
time.sleep(1)
response, content = http.request(uri=uri, method='GET')
content = json.loads(content.decode('utf-8'))
statistics = content['node-connector'][0]['opendaylight-port-statistics:flow-capable-node-connector-statistics']
bytes2 = statistics['bytes']['transmitted']
#在检测到s3的1口流量空闲时发的流表
speed=float(bytes2-bytes1)/1
if speed !=0 :#获取有效的速度
if speed < 1000 :
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:3/flow-node-inventory:table/0/flow/1', body=h5_to_s3_1, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:3/flow-node-inventory:table/0/flow/2', body=mh5_to_s3_2, method='PUT',headers=headers)
#在检测到s2的1口流量满载时发的流表
else :
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:3/flow-node-inventory:table/0/flow/1', body=mh5_to_s3_1, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:3/flow-node-inventory:table/0/flow/2', body=h5_to_s3_2, method='PUT',headers=headers)
odl = OdlUtil('127.0.0.1', '8181')
odl.install_flow()
启动ODL并且安装插件
-
i.进入ODL文件夹,并在终端输入以下命令
./karaf
-
ii.安装feature,输入以下命令:
feature:install odl-restconf
feature:install odl-l2switch-switch-ui
feature:install odl-openflowplugin-all
feature:install odl-mdsal-apidocs
feature:install odl-dlux-core
feature:install odl-dlux-node
feature:install odl-dlux-yangui
- iii.打开浏览器访问
http://127.0.0.1:8181/index.html
,登陆进入ODL图形化界面
建立拓扑图,并连接ODL控制器
要创建的拓扑结构如下图所示
通过如下的py代码建立拓扑结构
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import RemoteController,CPULimitedHost
from mininet.link import TCLink
from mininet.util import dumpNodeConnections
class MyTopo( Topo ):
"Simple topology example."
def __init__( self ):
"Create custom topo."
# Initialize topology
Topo.__init__( self )
switch1 = []
switch2 = []
host = []
for i in range( 2 ):
sw = self.addSwitch( 's{}'.format( i + 1 ) )
switch1.append( sw )
for i in range( 2 ):
sw = self.addSwitch( 's{}'.format( i + 3 ) )
switch2.append( sw )
for i in range( 7 ):
hs = self.addHost( 'h{}'.format( i + 1 ) )
host.append( hs )
self.addLink( switch1[0], switch1[1] )
self.addLink( switch1[0], switch2[0] )
self.addLink( switch1[0], switch2[1] )
for i in range( 2 ):
sw = switch2[i]
self.addLink( sw, switch1[1] )
for i in range( 3 ):
self.addLink( host[i], switch1[0] )
for i in range( 2 ):
self.addLink( host[i+3], switch2[0] )
for i in range( 2 ):
self.addLink( host[i+5], switch2[1] )
topos = { 'mytopo': ( lambda: MyTopo() ) }
- 打开ODL创建拓扑结构,创建完成得到如下结果:
- 接着使用mininet的net方法查看各端口的连接情况:
- 使用pingall命令,在ODL图形化界面可以看到拓扑结构如下:
- 以S3交换机为例,布置负载均衡前查看其流表项:
- 使用iperf命令测试h5和h4与h1的链接时的带宽,查看拥塞状况:
- 调用负载均衡程序并执行,此时查看再次查看S3的流表,发现收到俩个流表:
- 调用负载均衡程序并执行,并再次测试h5和h4与h1的链接时的带宽:
- 采用负载均衡后,查看带宽.发现h5到h1的带宽明显增加(由Mb/s突破至Gb/s),h4到h1的带宽稍微增加。这是因为在负载均衡代码中我们采用的是当s3的1端口与s1的2端口上满载时,ODL就会下发1个优先级为101的流表,该流表的作用是将h5的发出来的包从s3的2端口先转发到s2的2端口再由s2的1端口转发至s1的1端口,这样就减轻了s1与s3相连端口的负载压力,从而达到使得h5与h1交流时的带宽显著增加
总结
-
姚彬锟:在本学期SDN选课初,我对SDN是什么真的是一无所知,而随着课程的深入,学习了越来越多的东西,建拓扑、下发流表、RYU控制器等等,让我逐步了解了一些SDN的知识,虽然平时的作业做的并不是很好,但是毕竟是学有所得。还有期末做的report,也让我对NFV的内容有了更深的了解和理解,本门学科没有期末考试,但是最后的大实验确实是有点让人头疼,只能说之前学习的掌握的不够好导致一些东西得经常百度,还有一个就是在SDN学习的过程中配置一些东西真的太痛苦了,尽管如此,本次实验也复习了许多前面的内容,也算有所收获,不亏。
-
朱宏:通过SDN这门课程,我掌握了mininet的使用方法、通过py代码建立拓扑,或者通过拖拉的形式建立拓扑、测试拓扑连接情况、下发流表、RYU控制器的一些使用方法等知识,不过虽然作业做到了这些,但是也并不能说精通,很多东西掌握的并不彻底,可能因为没有经常操作,很多东西都得重新回过头看前面的报告,所以其实只是有了一个比较粗略的了解。在本次的作业中,不仅重温了拓扑的创建,对mininet,ODL下发流表进行了复习,实现了负载均衡,我对整体的概念又有了新一步的认识。
-
张庆焰:在这门课之前,我是完全不知道软件定义网络是一门学什么的课,软件?网络?而经过课堂上老师的讲解,在加上辅助的几次实验,以及最后的report和大作业,我对这门课的理解也更深了一些,在几次的实验过程中,被一些配置搞得头昏脑涨,不过好在同学和助教老师的帮助,得以按时完全一些作业。我们的report的选题是NFV,而大作业选择的是负载均衡,通过这两样我对他们都有了更深的理解,特别是负载均衡的作业也让我对前面的创建拓扑和下发流表等一系列相关知识有了一定的复习。课程虽然短暂,但是也学到了一些基础理论知识和实践知识,但是以后有机会还是要百尺竿头更进一步。
-
吴永铭:回顾这个学期SDN的学习,实践过的很快,但是课程里面其实包含了一堆全新的概念,每次学习的内容都是“新鲜的”,要接触大量的生词、概念词,所以收获必须是有收获的,理论与实践的结合,至少让我对实验上的东西都有了一定的了解,对理论知识也就更进了一步,但是还是有很多概念并不是特别的明白,很多用法也并不是很透彻。通过这次的负载均衡大作业,我们从创建拓扑、下发流表、测试链路等一系列之前曾经学习的知识进行了复习以及一部分的拓展,让我理解的更深入了一些。
-
张周伟:回顾一学期的软件定义网络的学习,时间十分短暂,但是每次的课都是比较充实的,每次都能学习一些新的知识,完成一些比较“高端”的东西,但是虽然充实,有些东西难理解或者有些实验的配置不好搭,导致每次做实验都得花比较多的时间,并且参考别人做的内容才能够完成实验,不过做完之后也是有所收获的。而经过本次大作业,我对之前实验做过的东西,比如OpenFlow、Mininet、下发流表等作了一定的复习,同时也有了更加深入的理解,对软件定义网络的概念理解也也更加深入了。