RYU实验笔记(一):多RYU控制器连接拓扑以及相关流表操作

本文围绕单RYU连接拓扑和流表操作展开。介绍了RYU控制器端口及restAPI相关操作,阐述基于参数的拓扑脚本、自定义控制器类、用户(控制器群)类等内容。通过实例化和部署,实现多控制器控制拓扑及流表操作,后续将结合flask完善功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于单RYU连接拓扑和流表操作:


在构建这样一个拓扑并让多RYU控制器连接之前需要知道的几个重要信息:

一,RYU控制器有三个端口:

  • OFP_TCP_PORT = 6653,它用于连接向OVS交换机,作为监听端口
  • OFP_SSL_PORT = 6653 ,目前暂无用处
  • WSGI_PORT=8080,它用于进行一系列restAPI的相关操作。

(其中前面两个端口的信息存在ryu/ryu/ofproto/ofproto_common.py中)

二,restAPI的相关操作则可以在ryu/ryu/app/ofctl_rest.py中查看,其中描述流表的增删查看等等操作和具体代码

 

三,为使拓扑灵活度更强,特地设定了一种基于参数的拓扑,通过JSON类型的参数设置拓扑(这个JSON文件储存了主机个数IP地址交换机个数和链路等等),相关代码已传至Github,本次使用的只是一个简陋版基于参数的拓扑,以便于把重心放在“多RYU控制器”上,本次拓扑:

 
                 MASTER
                 ___|___   
          _____ /   |   \ _____
     ___ /     /    |    \     \ _____
    /   /     /     |     \     \     \
  c0    c1    c2    c3    c4     c5     c6 
   |    |     |     |     |      |      |
   s0   s1    s2    s3    s4     s5     s6
   /\   /\    /\    /\    /\     /\     /\
 h0 h1 h2 h3 h4 h5 h6 h7 h8 h9 h10 h11 h12 h13

需要:

  • 基于参数的拓扑脚本:拓扑的生成
  • 自定义控制器类脚本:功能的定义
  • 用户(控制器群)类:整个框架的实例化
  • 流表操作脚本:在实例上进行一系列操作
  • 两个终端:一个用于创建mininet,一个用于调用流表操作脚本
  • 环境:mininet,RYU

1:基于参数的拓扑脚本:

先写好基于参数的拓扑脚本,并尝试运行,(脚本懒得改模块了就一并搬过来了)这里的例子是创建了7个控制器,每1个控制器管辖1个交换机,每个交换机连接2个主机,相邻两个交换机之间相连,由图可见由于没有开启RYU控制器所以没有连接上控制器,所以pingall的时候也都ping不通

#!/usr/bin/python
from mininet.net import Mininet
from mininet.node import Controller, RemoteController, OVSSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel, info
from mininet.link import Link, Intf, TCLink
from mininet.topo import Topo
from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import Response
from ryu.app.wsgi import WSGIApplication
import logging
import os


def multiControllerNet(con_num=7, sw_num=7, host_num=14):
	"Create a network from semi-scratch with multiple controllers."
	controller_list = []
	switch_list = []
	host_list = []
	
	net = Mininet(controller=None, switch=OVSSwitch, link=TCLink)
	
	for i in xrange(con_num):
		name = 'controller%s' % str(i)
		c = net.addController(name, controller=RemoteController,ip='127.0.0.1',port=6661 + i)
		controller_list.append(c)
		print("*** Creating %s" % name)
	
	print("*** Creating switches")
	switch_list = [net.addSwitch('s%d' % n) for n in xrange(sw_num)]
	print(switch_list)
	print("*** Creating hosts")
	
	host_list = [net.addHost('h%d' % n) for n in xrange(host_num)]
	
	print("*** Creating links of host2switch.")
	
	for i in xrange(0, sw_num):
		net.addLink(switch_list[i], host_list[i * 2])
		net.addLink(switch_list[i], host_list[i * 2 + 1])
	
	print("*** Creating interior links of switch2switch.")
	
	
	for i in xrange(0, sw_num, sw_num / con_num):
		for j in xrange(sw_num / con_num):
			for k in xrange(sw_num / con_num):
				if j != k and j > k:
					net.addLink(switch_list[i + j], switch_list[i + k])
	
	print("*** Creating intra links of switch2switch.")
	for i in range(con_num-1):
		net.addLink(switch_list[i],switch_list[i+1])
	
	print("*** Starting network")
	
	net.build()
	for c in controller_list:
		c.start()
	
	_No = 0
	for i in xrange(0, sw_num, sw_num / con_num):
		for j in xrange(sw_num / con_num):
			switch_list[i + j].start([controller_list[_No]])
		_No += 1
	
	# print "*** Testing network"
	# net.pingAll()
	
	print("*** Running CLI")
	
	CLI(net)
	
	print("*** Stopping network")
	
	net.stop()


if __name__ == '__main__':
	setLogLevel('info')  # for CLI output
	multiControllerNet(con_num=7, sw_num=7, host_num=14)

2.自定义控制器类(Mycontroller):

它继承了mininetAPI里的原始控制器类,并调用restAPI的脚本,这里只写了一些些功能并没有完全把ofctl_rest.py里的功能都写出来(其中有几个flow是供来做参考的),其中的match_flow是自己定义的一种匹配方式:事先设定一个你想要的匹配域A,kind=1时把有包含A的流表取出来,kind=2时取其补集

#!/usr/bin/python
import os
import sys
import json
import re
import subprocess
import argparse
import logging
import ast
import parser
import requests
from flask import Flask
from flask import request
from flask import url_for
from flask import jsonify
from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import Response
from ryu.app.wsgi import WSGIApplication
#from mininet.net import Mininet
#from mininet.node import Switch, OVSSwitch, Ryu,RemoteController,Controller
sw='3'
swag='{"match":{"in_port": 1,"dl_dst":"00:00:00:00:00:02"}}'
flow1='{"dpid":3, "cookie": 1, "cookie_mask": 1,"table_id": 1,"idle_timeout": 300,"hard_timeout": 300,"priority": 35,"flags": 1,"match":{"in_port":1},"actions":[{"type":"OUTPUT","port": 2}]}'
flow2='{"dpid":3, "cookie": 1, "cookie_mask": 1,"table_id": 1,"idle_timeout": 300,"hard_timeout": 300, "priority": 1,"flags": 1,"match":{"in_port":1},"actions":[]}'
flow3='{"dpid":3, "cookie": 1, "cookie_mask": 1,"table_id": 1,"idle_timeout": 320,"hard_timeout": 340, "priority": 1,"flags": 2,"match":{"dl_dst": "00:00:00:00:00:01", "dl_src": "00:00:00:00:00:02", "in_port": 2},"actions":[]}'
flow4='{"dpid":3 ,"cookie": 1,"cookie_mask": 1,"table_id": 0,"idle_timeout": 30,"hard_timeout": 3000,"priority": 11111,"flags": 1,"match":{"dl_src":"00:00:00:00:00:02","dl_dst":"00:00:00:00:00:01"},"actions":[ { "type": "OUTPUT","port": 2}]}'
class MyController():
	def __init__(self,cip,cport):
		self.cip=cip
		self.cport=cport
		self.path='http://' + self.cip + ':' + self.cport
	#get the list of all switche
	
	def get_switches(self):
		item =  self.path+ '/stats/switches'
		tmpres = os.popen('curl %s -s' % item).readlines()
		ss = tmpres[0][:-1]
		ss = ss[1:]
		sl = ss.split(', ')
		return (sl)
	# get the desc of a single switch
	def get_switch_desc(sid):
		if self.findswitch(sid):
			item = self.path + '/stats/desc/' + sid
			tmpres = os.popen('curl  %s -s' % item).readlines()
			return (tmpres)
		else:
			return 0
	# get the flowtable of a single switch
	def get_flow_states(self,sid):
		if self.findswitch(sid):
			item = self.path + '/stats/flow/' + sid
			tmpres = os.popen('curl  %s -s' % item).readlines()
			flow_table  = json.loads(tmpres[0])
			return (flow_table)
		else:
			print('Error:not such a flowtable')
			return 'Error:not such a flowtable'
	# figure out whether sid is useful
	def findswitch(self,sid):
		if sid not in self.get_switches():
			print('Error:not such a switch')
			return 0
		else:
			return 1
        # match the flowtable of a single switch you want
	def match_flow(self, swag, sid, kind):
		if self.findswitch(sid):
			flow_table = self.get_flow_states(sid)
			table = json.loads(swag)
			print(table['match'])
			number = 0;
			location1 = [];
			location2 = [];
			for flow in flow_table[sid]:
				flag = 0;
				for element in flow['match']:
					if element in table['match']:
						if flow['match'][element] == table['match'][element]:
							flag = flag + 1;
						else:
							flag = -20;
				if flag > 0:
					print('flow' + str(number) + 'matchable')
					location2.append(number)
				else:
					print('flow' + str(number) + 'unmatchable')
					location1.append(number);
				number = number + 1;
			if kind == 1:
				flag = 0
				for i in location1:
					del flow_table[sid][i - flag]
					flag = flag + 1
			if kind == 2:
				flag = 0
				for i in location2:
					del flow_table[sid][i - flag]
					flag = flag + 1
			return flow_table
		else:
			return 0
	# add the flow
	def add_flow(self,flow):
		item=self.path+'/stats/flowentry/add'
		tmpres = os.popen('curl -X POST -d \'%s\' %s -s' %(flow,item)).readlines()
		return 'adding flow'
	# delete the flow with match and priority
	def del_flow_mp(self,flow):
		item=self.path+'/stats/flowentry/delete_strict'
		tmpres = os.popen('curl -X POST -d \'%s\' %s -s' %(flow,item)).readlines()
		return 'deleting flow'
	# delete the flow with match
	def del_flow_m(self,flow):
		item=self.path+'/stats/flowentry/delete'
		tmpres = os.popen('curl -X POST -d \'%s\' %s -s' %(flow,item)).readlines()
		return 'deleting flow'
	# delete all the flow
	def del_all_flow(self,sid):
		if self.findswitch(sid):
			item =self.path+'/stats/flowentry/clear/'+sid
			tmptres = os.system('curl -X DELETE %s -s'%item)
			return 'clear!'
		else:
			return 'Error:not such a switch'

3.用户(控制器群)类(master):

它继承了控制器类,通过它管控各个控制器,这里就展示两个最主要的功能,开启控制器和关闭控制器,其中可见开启控制器使用了tcp_listen_port&wsgi_port,为使端口不冲突,特地给每个控制器设置了不一样的端口,在配置端口的时候可事先使用netstats -ap查看端口的使用情况,至于关闭控制器功能则就是将其端口对应的进程所关闭

#!/usr/bin/python
from tf import MyController
from mininet.net import Mininet
from mininet.node import Controller, RemoteController, OVSSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel, info
from mininet.link import Link, Intf, TCLink
from mininet.topo import Topo
from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import Response
from ryu.app.wsgi import WSGIApplication
import logging
import time
import os
flow4='{"dpid":33 ,"cookie": 1,"cookie_mask": 1,"table_id": 0,"idle_timeout": 30,"hard_timeout": 3000,"priority": 11111,"flags": 1,"match":{},"actions":[ { "type": "OUTPUT","port":"controller"}]}'

class master(MyController):
	def __init__(self,cnum):
		self.cnum=cnum
		self.clist=[]
	def createcontroller(self):
		for i in range(0,self.cnum):
			tcp_port=6661+i;
			lis_port=9090+i;
			tcp_port=str(tcp_port)
			lis_port=str(lis_port)
			name='app'+str(i)
			item='ryu-manager ofctl_rest.py simple_switch_13.py --ofp-tcp-listen-port='+tcp_port+' --wsapi-port '+lis_port+'&'
			os.system(item)
			controller=MyController('0.0.0.0',lis_port)
			self.clist.append(controller)
	def clear(self):
		for i in range(0,self.cnum):
			command='''kill -9 $(netstat -nlp | grep :'''+str(9090+i)+''' | awk '{print $7}' | awk -F"/" '{ print $1 }')'''
			os.system(command)
			os.system("netstat -an|awk '/tcp/ {print $6}'|sort|uniq -c")
	

4.用户的实例化和相关部署和实施

写好一个简易流表操作脚本从而达到通过RYU进行流表操作的目的

#!/usr/bin/python
from rf import master
from tf import MyController
imoprt time
me=master(7)
me.createcontroller()
time.sleep(20)
for i in range(7):
	print(me.clist[i].get_flow_states(str(i)))
time.sleep(200)
for i in range(7):
	print(me.clist[i].get_flow_states(str(i)))
me.clear()

注意到这里有两个休眠期,在开启这个脚本的时候等待20秒是为了开启拓扑脚本,然后将获取到这个拓扑的每个交换机的流表,然后等待两百秒是为了进行pingall,然后再获取一次流表,如果没有错的话,第一次获取到的流表只有连向控制器的流表,而第二次就是有连向其他交换机接口的流表了

4.1开启流表操作脚本:

出现(进程号)wsgi starting up on http://0.0.0.0:wsgi_port就是开启成功了,开启成功后就有流了(0号交换机的编号出了点问题,不过不影响实验)

4.2开启拓扑脚本并观察流表

接下来再第一个休眠期里开启拓扑,休眠期过后可见这些控制器获取到的流表,可以看出其流表中的流表项都只有1个,那就是连接上控制器的那一个(u只是unicode码所致)

4.3在mininet上作ping测试,然后观察流表

在第二个休眠期pingall然后再次获取流表,光是1号交换机的流表就让人应接不暇,然后结束


总结:

  • 终于实现了多控制器控制拓扑并进行相关流表操作的目标
  • 功能性和灵活度有待完善
  • 后期将结合flask以及拓扑的GUI界面和还有网络测试功能,做到在web端创建基于参数的可视化网络并对它进行控制器控制以及网络测试测量
<think>好的,用户之前已经询问了如何搭建SDN环境,现在他们的问题是:“主机环境还可以是其他的吗”。我需要确定用户的具体需求。他们可能在使用其他操作系统或者硬件配置时遇到了问题,或者只是想了解是否有更选择。 首先,我应该回顾之前的回答,在之前的部分我提到推荐Ubuntu 20.04/22.04,因为兼容性好。现在用户想知道是否有其他选项,可能他们不想用Ubuntu,或者有特定的环境需求,比如Windows或macOS。 接下来,我需要考虑不同操作系统的可行性。Ubuntu确实是最佳选择,但用户可能有其他偏好。比如,有些用户可能习惯用Windows,或者公司环境限制使用特定系统。这时候,虚拟机或Docker可能是解决方案。另外,macOS用户可能想用Homebrew安装相关工具,但兼容性问题可能更。 硬件配置方面,用户可能想知道最低要求是否还能更低,或者是否有更高性能的需求。例如,如果用户只是想进行小规模实验,可能4GB内存也够用,但需要指出可能会有性能瓶颈。而对于大规模模拟,更高的配置是必要的。 容器化部署也是个重要点,特别是云环境或快速实验。Docker和Kubernetes的使用越来越普遍,用户可能希望了解如何在这些环境中部署SDN组件,这样可以更灵活地管理资源。 另外,用户可能对物理设备的扩展感兴趣,比如如何将物理交换机整合到SDN环境中。这里需要提到支持OpenFlow的硬件,并给出配置示例。 最后,用户可能遇到兼容性问题,比如不同控制器或交换机的版本冲突。需要提供常见问题的解决方法,比如使用虚拟环境或检查依赖项。 总结下来,用户需要的是更灵活的环境选择,无论是操作系统、硬件还是部署方式。我需要详细列出各种可能性,同时指出优缺点,帮助用户根据自己的实际情况做出选择。此外,要强调验证步骤的重要性,确保环境配置正确,避免后续问题。</think>--- ### **主机环境扩展选择** SDN实验环境的搭建并非严格依赖特定系统或硬件,以下是更灵活的环境配置方案: --- ### **操作系统扩展** 1. **非Ubuntu Linux发行版** - **Debian/CentOS**:需手动编译安装组件(如Mininet、OVS) ```bash # CentOS安装示例 sudo yum install git python3 gcc make git clone https://github.com/mininet/mininet ./mininet/util/install.sh -n3v ``` - **Arch Linux**:通过AUR仓库快速安装 ```bash yay -S mininet openvswitch ryu ``` 2. **Windows/macOS系统** - **虚拟机方案**: - 使用VirtualBox/VMware创建Ubuntu虚拟机(分配至少2核4GB资源) - 启用嵌套虚拟化提升性能 - **容器化方案**: ```bash # Windows PowerShell中使用Docker docker run -it --privileged ubuntu:22.04 apt update && apt install mininet openvswitch-switch ``` - **macOS原生支持**: ```bash brew install mininet/openvswitch/openvswitch ryu-manager需通过Python虚拟环境运行 ``` --- ### **二、硬件配置弹性调整** | **场景** | **推荐配置** | **典型用途** | |----------------|----------------------------|-------------------------| | 基础实验 | 2核CPU/4GB RAM/15GB存储 | 学习OpenFlow协议、小型拓扑 | | 进阶开发 | 8核CPU/16GB RAM/SSD硬盘 | 多控制器测试、SDN应用开发 | | 生产级模拟 | 16核CPU/64GB RAM/NVMe存储 | 大规模网络仿真(100+节点) | --- ### **三、容器化与云环境** 1. **Docker快速部署** - 预构建镜像加速搭建: ```bash docker pull iwaseyusuke/mininet docker run -it --rm --privileged iwaseyusuke/mininet ``` - 自定义Dockerfile集成Ryu: ```dockerfile FROM ubuntu:22.04 RUN apt update && apt install -y mininet openvswitch-switch python3-ryu ``` 2. **云平台部署** - AWS/GCP/Azure中: - 选择计算优化型实例(如AWS c5.xlarge) - 开启SR-IOV提升虚拟交换机性能 - 关键网络配置: ```bash # 允许OpenFlow协议穿透云防火墙 iptables -A INPUT -p tcp --dport 6653 -j ACCEPT ``` --- ### **四、混合物理/虚拟环境** 1. **树莓派集群** - 使用4台树莓派4B(4GB版)构建低成本实验平台: ```bash # 在主节点部署Ryu控制器 scp ryu.tar.gz pi@node1:~/ ssh pi@node1 "tar xzf ryu.tar.gz && cd ryu && python3 setup.py install" ``` - 性能指标:可承载约20个OVS实例 2. **连接物理交换机** - 配置华为CE6851交换机支持OpenFlow 1.3: ```bash openflow enable controller ip 192.168.1.100 port 6633 ``` - 验证命令:`display openflow controller` --- ### **五、环境验证关键步骤** 1. **基础连通性测试** ```bash # 在Mininet中创建测试拓扑 sudo mn --test pingall --controller=remote,ip=127.0.0.1 ``` $$ \text{丢包率} = \frac{\text{未响应ICMP报文数}}{\text{总发送数}} \times 100\% $$ 要求:丢包率 < 0.5% 2. **流表下发延迟测量** ```bash # 使用Ryu的ofproto_parser抓取事件 ryu-manager ryu.app.ofctl_rest --observe-links ``` 合格标准:首包处理延迟 < 50ms --- ### **六、特殊环境注意事项** 1. **Windows子系统(WSL)限制**: - WSL 1不支持完整的Linux网络栈,需升级到WSL 2 - 需手动加载Open vSwitch内核模块: ```bash sudo modprobe openvswitch sudo ovsdb-server --remote=punix:/var/run/openvswitch/db.sock & ``` 2. **低配设备优化技巧**: - 关闭图形界面:`sudo systemctl set-default multi-user.target` - 限制Mininet资源: ```bash sudo mn --topo tree,2,2 --mac --switch ovsk \ --controller remote --cpu 0.5 --mem 10% ``` --- ### **七、环境选择建议** | **需求场景** | **推荐方案** | **优势** | |----------------------|--------------------------|-------------------------| | 教学演示/快速验证 | Ubuntu虚拟机+Docker | 快速重置、隔离性强 | | 协议开发/长期研究 | 物理服务器+原生Ubuntu | 性能稳定、调试方便 | | 跨平台测试 | 云环境+Kubernetes集群 | 弹性扩展、节点管理 | 通过灵活组合上述方案,可在从笔记本电脑到数据中心的各类环境中构建适用的SDN实验平台。建议初次接触SDN的用户优先使用**Ubuntu 22.04虚拟机方案**,待熟悉基础操作后再尝试混合环境部署。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值