这是基于RYU+Mininet的SDN架构设计仿真校园网络的第一部分
总体详见:【基本中型网络的仿真(RYU+Mininet的SDN架构)-以校园为例】
章节:
【RYU+Mininet的SDN架构-设计校园网络(一)】【RYU+Mininet的SDN架构-设计校园网络(二)】https://blog.csdn.net/weixin_53284122/article/details/129393371
【RYU+Mininet的SDN架构-设计校园网络(二)】
【RYU+Mininet的SDN架构-设计校园网络(三)】
【RYU+Mininet的SDN架构-设计校园网络(四)】
【RYU+Mininet的SDN架构-设计校园网络(五)】
SDN采用RYU控制器和mininet的方式,交换机采用的是openflow13协议。
主要是涉及Mininet和RYU控制器的安装,一起路由定义软件Quagga的安装和配置。
详细的配置步骤在网络上都可以找到,在此不在叙述。
第一步:打开RYU控制器,运行相应的程序(比如simple_switch_13.py默认路由,rest_firewall.py防火墙程序)
第二步:运行拓扑代码,连接到控制器
ospf采用quagga实现,需要对每个路由器配置相应的守护进程,在通过命令行开启ospf算法,最终实现路由的收敛。
(1)配置
1.在quagga安装目录里写配置文件
r1ospfd.conf(设置r1的直连网络) |
hostname r1_ospfd password 123 enable password 123 router ospf ospf router-id 192.168.3.2 network 192.168.3.0/30 area 0 network 192.168.3.4/30 area 0 network 192.168.10.0/30 area 0 debug ospf event log stdout |
hostname r1_ospfd
password 123
enable password 123
router ospf
ospf router-id 192.168.3.2
network 192.168.3.0/30 area 0
network 192.168.3.4/30 area 0
network 192.168.10.0/30 area 0
debug ospf event
log stdout
r2ospfd.conf(设置r2的直连网络) |
hostname r2_ospfd password 123 enable password 123 router ospf ospf router-id 192.168.3.1 network 192.168.1.0/24 area 0 network 192.168.3.0/30 area 0 debug ospf event log stdout |
hostname r2_ospfd
password 123
enable password 123
router ospf
ospf router-id 192.168.3.1
network 192.168.1.0/24 area 0
network 192.168.3.0/30 area 0
debug ospf event
log stdout
r3ospfd.conf(设置r3的直连网络) |
hostname r3_ospfd password 123 enable password 123 router ospf ospf router-id 192.168.3.6 network 192.168.2.0/24 area 0 network 192.168.3.4/30 area 0 debug ospf event log stdout |
hostname r3_ospfd
password 123
enable password 123
router ospf
ospf router-id 192.168.3.6
network 192.168.2.0/24 area 0
network 192.168.3.4/30 area 0
debug ospf event
log stdout
r1zebra.conf、r2zebra.conf、r3zebra.conf 3个文件无需额外配置,直接复制示例模板即可。
2.命令行启动quagga及运行
命令行打开quagga软件,命令如下:
sudo zebra -d |
软件打开后,在拓扑代码final.py中嵌入以下命令,运行ospf:
r1.cmd('zebra -f /etc/quagga/r1zebra.conf -d -z /tmp/r1zebra.api -i /tmp/r1zebra.interface') r2.cmd('zebra -f /etc/quagga/r2zebra.conf -d -z /tmp/r2zebra.api -i /tmp/r2zebra.interface') r3.cmd('zebra -f /etc/quagga/r3zebra.conf -d -z /tmp/r3zebra.api -i /tmp/r3zebra.interface') time.sleep(1) # time for zebra to create api socket r1.cmd('ospfd -f /etc/quagga/r1ospfd.conf -d -z /tmp/r1zebra.api -i /tmp/r1ospfd.interface') r2.cmd('ospfd -f /etc/quagga/r2ospfd.conf -d -z /tmp/r2zebra.api -i /tmp/r2ospfd.interface') r3.cmd('ospfd -f /etc/quagga/r3ospfd.conf -d -z /tmp/r3zebra.api -i /tmp/r3ospfd.interface') |
r1.cmd('zebra -f /etc/quagga/r1zebra.conf -d -z /tmp/r1zebra.api -i /tmp/r1zebra.interface')
r2.cmd('zebra -f /etc/quagga/r2zebra.conf -d -z /tmp/r2zebra.api -i /tmp/r2zebra.interface')
r3.cmd('zebra -f /etc/quagga/r3zebra.conf -d -z /tmp/r3zebra.api -i /tmp/r3zebra.interface')
time.sleep(1) # time for zebra to create api socket
r1.cmd('ospfd -f /etc/quagga/r1ospfd.conf -d -z /tmp/r1zebra.api -i /tmp/r1ospfd.interface')
r2.cmd('ospfd -f /etc/quagga/r2ospfd.conf -d -z /tmp/r2zebra.api -i /tmp/r2ospfd.interface')
r3.cmd('ospfd -f /etc/quagga/r3ospfd.conf -d -z /tmp/r3zebra.api -i /tmp/r3ospfd.interface')
(2)实现
通过直接运行final.py文件
图4-1启动ospf操作示意图
Stp采用ryu控制器实现,通过设置可以处理的流表类型来允许处理BDPU包,从而开启stp,实现防止环路形成/链路恢复。
(1)配置
在ryu的模块simple_switch_13.py中配置
simple_switch_13.py |
…… …… from ryu.lib import stplib #改变1:引入stplib,以支持STP协议 class SimpleSwitch13(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] _CONTEXTS = {'stplib': stplib.Stp} #改变2:指定STP协议参考类 …… …… #@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) @set_ev_cls(stplib.EventPacketIn, MAIN_DISPATCHER)#改变3:将EventOFPPacketIn 换成EventPacketIn,后者封装了前者,且可以处理BDPU包 …… …… |
……
……
from ryu.lib import stplib #改变1:引入stplib,以支持STP协议
class SimpleSwitch13(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
_CONTEXTS = {'stplib': stplib.Stp} #改变2:指定STP协议参考类
……
……
#@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
@set_ev_cls(stplib.EventPacketIn, MAIN_DISPATCHER)#改变3:将EventOFPPacketIn 换成EventPacketIn,后者封装了前者,且可以处理BDPU包
(2)实现
由于是直接在ryu控制器中进行设置,那么无需在拓扑代码中再进行设置,直接运行拓扑文件final.py文件即可。
图4-2启动stp操作示意图
4.4 DHCP设计配置与实现
DHCP采用的是下载额外的DHCP服务器,然后通过mininet自带的host.defaultIntf.updateIP()函数进行IP地址的更新。
checkRequired()函数检查各项配置 |
def checkRequired(): "Check for required executables" required = [ 'udhcpd', 'udhcpc', 'dnsmasq', 'curl', 'firefox' ] for r in required: if not quietRun( 'which ' + r ): print '* Installing', r print quietRun( 'apt-get install -y ' + r ) if r == 'dnsmasq': print quietRun( 'update-rc.d dnsmasq disable' ) |
def checkRequired():
"Check for required executables"
required = [ 'udhcpd', 'udhcpc', 'dnsmasq', 'curl', 'firefox' ]
for r in required:
if not quietRun( 'which ' + r ):
print '* Installing', r
print quietRun( 'apt-get install -y ' + r )
if r == 'dnsmasq':
print quietRun( 'update-rc.d dnsmasq disable' )
(1)实现
主要流程如下图:
图4-3 DHCP运行流程图
下面介绍各个流程核心代码
地址池的设置(例子) |
DNSTemplate = """ start #开始IP end #结束IP option subnet #子网掩码 option domain local option lease 7 # seconds """ |
DNSTemplate = """
start #开始IP
end #结束IP
option subnet #子网掩码
option domain local
option lease 7 # seconds
"""
创建DHCP服务器.conf文件 |
def makeDHCPconfig( filename, intf, gw, dns ): "Create a DHCP configuration file" config = ( 'interface %s' % intf, DNSTemplate, 'option router %s' % gw, 'option dns %s' % dns, '' ) with open( filename, 'w' ) as f: f.write( '\n'.join( config ) ) |
def makeDHCPconfig( filename, intf, gw, dns ):
"Create a DHCP configuration file"
config = (
'interface %s' % intf,
DNSTemplate,
'option router %s' % gw,
'option dns %s' % dns,
'' )
with open( filename, 'w' ) as f:
f.write( '\n'.join( config ) )
启动DHCP服务器 |
def startDHCPserver( host, gw, dns ): "Start DHCP server on host with specified DNS server" info( '* Starting DHCP server on', host, 'at', host.IP(), '\n' ) dhcpConfig = '/tmp/%s-udhcpd.conf' % host makeDHCPconfig( dhcpConfig, host.defaultIntf(), gw, dns ) host.cmd( 'udhcpd -f', dhcpConfig, '1>/tmp/%s-dhcp.log 2>&1 &' % host ) |
def startDHCPserver( host, gw, dns ):
"Start DHCP server on host with specified DNS server"
info( '* Starting DHCP server on', host, 'at', host.IP(), '\n' )
dhcpConfig = '/tmp/%s-udhcpd.conf' % host
makeDHCPconfig( dhcpConfig, host.defaultIntf(), gw, dns )
host.cmd( 'udhcpd -f', dhcpConfig,
'1>/tmp/%s-dhcp.log 2>&1 &' % host )
启动请求方,并创建.log文件 |
def startDHCPclient( host ): "Start DHCP client on host" intf = host.defaultIntf() host.cmd( 'dhclient -v -d -r', intf ) host.cmd( 'dhclient -v -d 1> /tmp/dhclient.log 2>&1', intf, '&' ) |
def startDHCPclient( host ):
"Start DHCP client on host"
intf = host.defaultIntf()
host.cmd( 'dhclient -v -d -r', intf )
host.cmd( 'dhclient -v -d 1> /tmp/dhclient.log 2>&1', intf, '&' )
请求方等待IP地址,若失败则进行重复请求 |
def waitForIP( host ): "Wait for an IP address" info( '*', host, 'waiting for IP address' ) while True: host.defaultIntf().updateIP() if host.IP(): break info( '.' ) sleep( 1 ) info( '\n' ) |
至此,DHCP分配结束。
def waitForIP( host ):
"Wait for an IP address"
info( '*', host, 'waiting for IP address' )
while True:
host.defaultIntf().updateIP()
if host.IP():
break
info( '.' )
sleep( 1 )
info( '\n' )
NAPT的配置在拓扑代码里实现。通过以下代码在拓扑中加入NAT节点。
NAT节点添加代码 |
nat0 = self.addNode('nat0', cls=NAT, ip='192.168.10.1/30', subnet='192.168.0.0/16', inNamespace=False) |
其中subnet属性用于配置nat节点所负责的子网范围,只有处于subnet内的主机通信时,nat节点才会为其提供转换。
之后我们还要为所有节点配置默认路由,并为nat节点配置路由使得外面发送的信息能够成功传入Mininet内。
默认路由配置代码 |
r1.cmd('route add default gw 192.168.10.1 dev r1-eth3') r2.cmd('route add default gw 192.168.3.2 dev r2-eth1') r3.cmd('route add default gw 192.168.3.5 dev r3-eth1') nat0.cmd('route add -net 192.168.0.0/16 gw 192.168.10.2 dev nat0-eth1') |
r1.cmd('route add default gw 192.168.10.1 dev r1-eth3')
r2.cmd('route add default gw 192.168.3.2 dev r2-eth1')
r3.cmd('route add default gw 192.168.3.5 dev r3-eth1')
nat0.cmd('route add -net 192.168.0.0/16 gw 192.168.10.2 dev nat0-eth1')
通过以上配置之后,Mininet内的主机便可以与外界主机通信了。
防火墙采用的是RYU控制器,通过在RYU控制器中的防火墙程序(rest_firewall.py)文件进行实现。
(1)配置
1.通过编写代码设置防火墙规则
Firewall.py(实现防火墙的过滤规则) |
import requests data1='{"nw_src":"192.168.1.1","nw_dst":"192.168.2.1"}' data2='{"nw_src":"192.168.2.1","nw_dst":"192.168.1.1"}' data3='{"nw_src":"192.168.2.2","nw_dst":"192.168.1.1"}' data4='{"nw_src":"192.168.1.1","nw_dst":"192.168.2.2"}' def firewall(): # set rules for switch by ryu/ryu.app/rest_firewall.py # data1-data4 is the rule by myself) response = requests.put('http://localhost:8080/firewall/module/enable/0000 000000000004') response= requests.post('http://127.0.0.1:8080/firewall/rules/0000000000000004', data=data1) response = requests.post('http://127.0.0.1:8080/firewall/rules/0000000000000004', data=data2) response = requests.post('http://127.0.0.1:8080/firewall/rules/0000000000000004', data=data3) response = requests.post('http://127.0.0.1:8080/firewall/rules/0000000000000004', data=data4) firewall() |
import requests
data1='{"nw_src":"192.168.1.1","nw_dst":"192.168.2.1"}'
data2='{"nw_src":"192.168.2.1","nw_dst":"192.168.1.1"}'
data3='{"nw_src":"192.168.2.2","nw_dst":"192.168.1.1"}'
data4='{"nw_src":"192.168.1.1","nw_dst":"192.168.2.2"}'
def firewall():
# set rules for switch by ryu/ryu.app/rest_firewall.py
# data1-data4 is the rule by myself)
response = requests.put('http://localhost:8080/firewall/module/enable/0000
000000000004')
response=
requests.post('http://127.0.0.1:8080/firewall/rules/0000000000000004',
data=data1)
response = requests.post('http://127.0.0.1:8080/firewall/rules/0000000000000004', data=data2)
response = requests.post('http://127.0.0.1:8080/firewall/rules/0000000000000004', data=data3)
response = requests.post('http://127.0.0.1:8080/firewall/rules/0000000000000004', data=data4)
firewall()
2.命令行设置防火墙规则
命令行打开S4,设置为可以enable状态,配置命令如下:
curl -X PUT http://localhost:8080/firewall/module/enable/0000000000000004 |
之后在enable状态下,在链接到RYU控制器后台设置防火墙的过滤规则。
curl -X POST -d '{"nw_src":"192.168.2.1/32","nw_dst":"192.168.1.1/32"}' http://127.0.0.1:8080/firewall/rules/0000000000000004 curl -X POST -d '{"nw_src":"192.168.1.1/32","nw_dst":"192.168.2.1/32"}' http://127.0.0.1:8080/firewall/rules/0000000000000004 |
(2)实现
1)启动控制器C1的终端,启动RYU控制器的防火墙程序
图4-4 启动防火墙操作示意图
图4-5 启动设置防火墙规则操作示意图
WLAN部分的实现以代码为主,以下展示具体的实现思路和核心代码。
(1)设置网络类型为Mininet-WiFi,并配置控制器
设置网络类型为Mininet-WiFi,并配置控制器 |
net = Mininet_wifi(topo=None, build=False, link=wmediumd , wmediumd_mode=interference) info('***Adding controllerln ' ) c1= net.addController( name= 'c1 ',controller=Controller, protocol= 'tcp ' ,port=6653) |
net = Mininet_wifi(topo=None,
build=False,
link=wmediumd ,
wmediumd_mode=interference)
info('***Adding controllerln ' )
c1= net.addController( name= 'c1 ',controller=Controller, protocol= 'tcp ' ,port=6653)
(2)配置AP的名称、MAC地址、SSID、信道编号、加密方式、密码和物理位置。
配置AP(以AP1为例) |
ap1 = net.addAccessPoint( 'ap1', mac='00:00:00:00:00:01', ssid="handover",mode="g", channel="1", passwd= '123456789a',encrypt='wpa2', position='123.0,323.0,0') |
ap1 = net.addAccessPoint( 'ap1', mac='00:00:00:00:00:01', ssid="handover",mode="g", channel="1", passwd= '1234567
(3)配置站点的名称、IP地址、物理位置、扫描信号强度门限、短间隔、长间隔和扫描模式。
配置站点(以sta1为例) |
sta1 = net.addStation( 'sta1', ip= '192.168.4.1/24',position= '54.0,434.0,0 ', bgscan_threshold=-60,s_inverval=5, l_interval=10,bgscan_module="simpie") |
(4)设置无线信号的指数传播模型
设置无线信号的指数传播模型 |
net.setPropagationModel( model="logDistance" , exp=3) |
为了实现两个Mininet网络的互连,我们首先需要在两个Ubuntu虚拟机上各再创建一张新的网卡。创建新网卡后,需要将新添加的网卡与Open vSwitch交换机端口绑定。具体实现过程如下:
①在两个Ubuntu虚拟机上各再创建一张新的网卡。添加新的虚拟机网卡需要在VMware Player中设置,如图。
图4-6 创建一张新的网卡
②进入虚拟机,释放新添加的虚拟机网卡。使用的具体命令如图。
图4-7 释放虚拟机网卡使用的命令
③然后将两台虚拟机中新创建的虚拟网卡绑定到同一VMnet网卡上(即下图的VMnet0),并且需要将对应VMnet设置成桥接模式。
图4-8 虚拟机网卡配置
从上图可以看出,VMnet0网卡桥接到了物理主机的无线网卡(Microsoft-WiFi Direct Virtual Adapter)上,因此,我们可以画出如下的设备连接逻辑图。
图4-9 占用网卡后的无线网网络拓扑
④将OVS交换机端口与刚释放出来的虚拟网卡相绑定。使用的代码如下:
代码-将OVS交换机端口与刚释放出来的虚拟网卡相绑定 |
import os …… os. popen( 'ovs-vsctl add-port s1 ens34 ') |