一.实验代码
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))
#s2流表
#h2工作时s2端口1流量空闲时下发的流表
h2_to_s2_1 ='{"flow": [{"id": "0","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.2/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"}]}'
#h3工作时s2端口1流量空闲时下发的流表
h3_to_s2_1 ='{"flow": [{"id": "1","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.3/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"}]}'
mh3_to_s2_1 ='{"flow": [{"id": "1","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.3/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"}]}'
#h3工作时s2端口1流量满载时下发的流表
h3_to_s2_2 ='{"flow": [{"id": "2","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.3/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"}]}'
mh3_to_s2_2 ='{"flow": [{"id": "2","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.3/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"}]}'
#s3流表
s3_1='{"flow": [{"id": "0","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.3/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"}]}'
s3_2='{"flow": [{"id": "1","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.3/32"},'\
'"instructions": {"instruction": [{"order": "0",'\
'"apply-actions": {"action": [{"output-action": {'\
'"output-node-connector": "2"},"order": "0"}]}}]},'\
'"priority": "101","cookie": "2","table_id": "0"}]}'
#s1流表
s1_2To1='{"flow": [{"id": "0","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.2/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_3To1='{"flow": [{"id": "1","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.3/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"}]}'
#h1工作时s1端口2流量空闲时下发的流表
h1_to_s1_2 ='{"flow": [{"id": "2","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.3/32"},'\
'"instructions": {"instruction": [{"order": "0",'\
'"apply-actions": {"action": [{"output-action": {'\
'"output-node-connector": "2"},"order": "0"}]}}]},'\
'"priority": "101","cookie": "2","table_id": "0"}]}'
mh1_to_s1_2 ='{"flow": [{"id": "3","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.3/32"},'\
'"instructions": {"instruction": [{"order": "0",'\
'"apply-actions": {"action": [{"output-action": {'\
'"output-node-connector": "2"},"order": "0"}]}}]},'\
'"priority": "100","cookie": "3","table_id": "0"}]}'
#h1工作时s1端口2流量满载时下发的流表
h1_to_s1_3 ='{"flow": [{"id": "2","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.3/32"},'\
'"instructions": {"instruction": [{"order": "0",'\
'"apply-actions": {"action": [{"output-action": {'\
'"output-node-connector": "3"},"order": "0"}]}}]},'\
'"priority": "101","cookie": "2","table_id": "0"}]}'
mh1_to_s1_3 ='{"flow": [{"id": "3","match": {"ethernet-match":'\
'{"ethernet-type": {"type": "2048"}},'\
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.3/32"},'\
'"instructions": {"instruction": [{"order": "0",'\
'"apply-actions": {"action": [{"output-action": {'\
'"output-node-connector": "3"},"order": "0"}]}}]},'\
'"priority": "100","cookie": "3","table_id": "0"}]}'
headers = {'Content-type': 'application/json'}
num=0
#下发流表,地址由ODL上获得
#下发s1与s3的流表
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_2To1, 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_3To1, 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/0', body=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/0', body=s3_2, method='PUT',headers=headers)
#s2调用h2到1的流表
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=h2_to_s2_1, method='PUT',headers=headers)
while num < 4 :
s1_uri = 'http://127.0.0.1:8181/restconf/operational/opendaylight-inventory:nodes/node/openflow:1/node-connector/openflow:1:2'
s2_uri = 'http://127.0.0.1:8181/restconf/operational/opendaylight-inventory:nodes/node/openflow:2/node-connector/openflow:2:1'
#获取s1端口2的流量
response, content = http.request(uri=s1_uri, method='GET')
content = json.loads(content)
statistics = content['node-connector'][0]['opendaylight-port-statistics:flow-capable-node-connector-statistics']
s1_bytes1 = statistics['bytes']['transmitted']
#0.5秒后再次获取
time.sleep(0.5)
response, content = http.request(uri=s1_uri, method='GET')
content = json.loads(content)
statistics = content['node-connector'][0]['opendaylight-port-statistics:flow-capable-node-connector-statistics']
s1_bytes2 = statistics['bytes']['transmitted']
s1_speed=float(s1_bytes2-s1_bytes1)/0.5
if s1_speed !=0 :#获取有效的速度
print ('s1端口2速度:')
print s1_speed
#在检测到s1端口2流量空闲时发的流表
if s1_speed < 1000 :
print(' s1端口2空闲,h1数据包改为往s1端口2通过')
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/2', body=h1_to_s1_2, 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/3', body=mh1_to_s1_2, method='PUT',headers=headers)
#在检测到s1端口2流量满载时发的流表
else :
print(' s1端口2满载,h1数据包改为往s1端口3通过')
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/2', body=h1_to_s1_3, 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/3', body=mh1_to_s1_3, method='PUT',headers=headers)
#获取s2端口1的流量
response, content = http.request(uri=s2_uri, method='GET')
content = json.loads(content)
statistics = content['node-connector'][0]['opendaylight-port-statistics:flow-capable-node-connector-statistics']
s2_bytes1 = statistics['bytes']['transmitted']
#0.5秒后再次获取
time.sleep(0.5)
response, content = http.request(uri=s2_uri, method='GET')
content = json.loads(content)
statistics = content['node-connector'][0]['opendaylight-port-statistics:flow-capable-node-connector-statistics']
s2_bytes2 = statistics['bytes']['transmitted']
s2_speed=float(s2_bytes2-s2_bytes1)/0.5
if s2_speed !=0 :#获取有效的速度
print ('s2端口1速度:')
print s2_speed
#在检测到s2端口1流量空闲时发的流表
if s2_speed < 1000 :
print(' s2端口1空闲,h3数据包改为往s2端口1通过')
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/1', body=h3_to_s2_1, 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/2', body=mh3_to_s2_2, method='PUT',headers=headers)
#在检测到s2端口1流量满载时发的流表
else :
print(' s2端口1满载,h3数据包改为往s2端口2通过')
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/1', body=mh3_to_s2_1, 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/2', body=h3_to_s2_2, method='PUT',headers=headers)
odl = OdlUtil('127.0.0.1', '8181')
odl.install_flow()
二.实验场景
服务器h2 h3上各自有不同的服务,h1是客户端。实现一个负载均衡的北向程序,当h2和h3向h1传输数据时,北向应用根据链路的使用状况动态的调整路由规则。
主要思路:过一定的时间后,下发新的流表,使得流量流向另一个交换机,从而实现负载均衡。类似于轮询法。
三.小组分工
- 负责根据队友所找的相关资料以及所选的拓扑来进行场景的设计与流表的编写,同是与队友共同进行代码编写以及后续的修改。
四、课程总结
首先对这学期的学习进行一个回顾总结
1、实践操作:
- 对ubuntu操作系统有了进一步的了解。
- 安装mininet,用字符命令、可视化界面、Python脚本等生成拓扑,并测试连通性。
- 安装floodlight,生成拓扑并连接控制器floodlight,利用控制器floodlight查看图形拓扑,利用字符界面下发流表,来验证openflow的hardtime机制。
- 利用OVS命令下发流表和查看流表,实现VLAN功能。
- Wireshark抓包验证。
- 利用ODL下发流表,借助Postman通过ODL的北向接口下发流表,再利用ODL北向接口查看已下发的流表。
- 利用ODL下发组表、流表,实现负载均衡,利用Wireshark验证负载均衡的实现。
2.对SDN的认识:
(1)了解了SDN:
- 软件定义网络(Software Defined Network, SDN ),是Emulex网络一种新型网络创新架构,是网络虚拟化的一种实现方式,其核心技术OpenFlow通过将网络设备控制面与数据面分离开来,从而实现了网络流量的灵活控制,使网络作为管道变得更加智能。
(2)SDN基本思想:
- 利用分层的思想,SDN将数据与控制相分离。在控制层,包括具有逻辑中心化和可编程的控制器,可掌握全局网络信息,方便运营商和科研人员管理配置网络和部署新协议等。在数据层,包括哑的交换机,交换机仅提供简单的数据转发功能,可以快速处理匹配的数据包,适应流量日益增长的需求.两层之间采用开放的统一接口进行交互。控制器通过标准接口向交换机下发统一标准规则,交换机仅需按照这些规则执行相应的动作即可。
(3)SDN优势:
- SDN 技术能够有效降低设备负载,协助网络运营商更好地控制基础设施,降低整体运营成本。
- SDN解放了手工操作,减少了配置错误,易于统一快速部署。
(4)了解了mininet
- Mininet是由一些虚拟的终端节点(end-hosts)、交换机、路由器连接而成的一个网络仿真器,它采用轻量级的虚拟化技术使得系统可以和真实网络相媲美。
- Mininet可以很方便地创建一个支持SDN的网络:host就像真实的电脑一样工作,可以使用ssh登录,启动应用程序,程序可以向以太网端口发送数据包,数据包会被交换机、路由器接收并处理。有了这个网络,就可以灵活地为网络添加新的功能并进行相关测试,然后轻松部署到真实的硬件环境中。
(5)了解了OpenFlow流表:
- OpenFlow的每个流表项都由3部分组成:
- 用于数据包匹配的包头域(Header Fields);
- 用于统计匹配数据包个数的计数器(Counters);
- 用于展示匹配的数据包如何处理的动作(Actions)。
- OpenFlow流表的优点:
多级流表将数据包的处理逻辑划分为多个子逻辑,并由多张流表分别来匹配和处理,从而使得数据包的处理变成了一条流水线。单流表是无法满足复杂的业务逻辑要求的。
多级流表的设计使得流表项聚合成为可能,节省了流表空间,可减少流表项个数,也提高了编程处理逻辑的灵活性。
(6)SDN控制器:
- POX:完全使用Python语言编写,采用与NOX一直的事件处理机制和编程模式,增加了多线程支持,
- Floodlight:是基于Java语言的开源SDN控制器,当前支持的南向协议为OpenFlow1.0协议。
- OpenContrail: 是由 Juniper 推出的基于 C++的 SDN 控制器,提供了用于网络虚拟化的基本组件。
- Ryu:是基于 Python 语言的 开源 SDN 控制器。提供的完备 API 有助于网络运营者高效便捷地开发 SDN 管理和控制应用。
- onos:架构专注于电信运营商领域控制器关键需求:高可扩展性,高性能,高实时性,高可靠性。
(7)等价多路径(Equal-CostMultipathRouting):
- 存在多条不同链路到达同一目的地址的网络环境中
- 当设备支持等价路由时,发往该目的 IP 或者目的网段的三层转发流量就可以通过不同的路径分担,实现网络的负载均衡,并在其中某些路径出现故障时,由其它路径代替完成转发处理,实现路由冗余备份功能。
(8)负载均衡(Load Balance):
- 单个重负载的运算分担到多台节点设备上做并行处理,每个节点设备处理结束后,将结果汇总,返回给用户,系统处理能力得到大幅度提高,这就是常说的集群(clustering)技术。
- 大量的并发访问或数据流量分担到多台节点设备上分别处理,减少用户等待响应的时间,这主要针对Web服务器、FTP服务器、企业关键应用服务器等网络应用。
3、个人感受:
- SDN这门课程在理论知识方面给我带来了不小的收获,让我了解到了一些从来没有接触过的东西和理论,虽然现在网络无处不在,但是在上这门课之前,我对网络的认识还十分有限,对网络的理解还仅仅停留在表面。经过了这门课程的学习,我对网络有了新的认识,我明白了网速的快慢不仅仅取决于网络设备的性能,还取决于调配网络资源的方案。SDN是在物理的网络上面架设了一层虚拟的网络,通过这个虚拟的网络对物理网络上的资源进行合理的分配,能极大的提高物理链路的利用率,从而达到提升网络质量的效果。“软件定义网络”,让我明白了在网络不仅仅取决于“硬件”,还取决于“软件”。
- 同时这门课又是一门实践课,经过了几次的上机练习,我不仅对SDN有了更全面的了解,也对ubuntu有了更进一步的理解,同时这门课程也使我接触到了一门新的语言,python。之前只是有听说过这门语言,而经过这门课程的学习让我对这门语言有了初步的认识。在学习这门课程的过程中一定程度上也提升了我的编码能力。