我是OpenFlow和SDN的新手。 我需要在Ubuntu或Debian机器上设置Ryu OpenFlow控制器的帮助,并了解一个基本的Ryu应用程序。
注意 :这个问题已经有了答案。
这可能是我在Stack Overflow上写的最长的帖子之一。 我一直在学习OpenFlow,SDN和Ryu,并想在这里记录我的初学者的知识。 如果需要,请纠正/编辑我的帖子。
这个简短的指南假设你已经有计算机网络和主要网络协议的知识。 本指南将帮助您从系统设置开始使用OpenFlow。
请阅读OpenFlow – Open Networking Foundation 。
进一步阅读: 网络的未来,以及Scott Shenker和软件定义网络协议的过去,IEEE INFOCOM 2009 。
在你开始之前:
基础设施层包括网络核心内的路由器和交换机。
控制层包括运行OpenFlow控制器的PC以及控制器本身。
应用程序层包含在该控制器上运行的应用程序。 在Ryu中,这些应用程序是用Python编写的。
OpenFlow是基础设施和控制层交互使用的协议。 OpenFlow不提供自己的API。 这是一个开源协议,供开发OpenFlow交换机的供应商和编写控制器的开发人员使用,如Ryu。 该API由控制器提供。
先决条件
你需要互联网接入。 如果您在虚拟机中运行Debian,请发出以下命令,通过NAT自动配置您的以太网接口:
su dhclient eth0
启用sudo
Debian默认不会使用sudo。 稍后您将使用的某些Ryu应用程序需要sudo。 您可以安装sudo并将自己添加到sudo'ers列表中,如下所示:
su apt-get install sudo # you might need to do apt-get update first! nano /etc/sudoers
找到说%sudo ALL =(ALL:ALL)ALL的行,并在其下面添加一个条目:
yourusername ALL=(ALL:ALL) ALL
按CTRL + X,然后按Y将更改保存到sudoers文件。 现在你可以以root身份注销,返回到你自己的shell
exit
启用最佳屏幕分辨率(仅限VM)
如果您在Virtual Box中运行Debian,则默认安装不会启用Virtual Box的全屏分辨率支持。 您将在第3节稍后介绍更大的屏幕。现在启用它是一个好主意。
在虚拟机窗口中,单击设备>插入客人添加CD图像…
然后cd到包含文件的目录
cd /media/cdrom
由于权限问题,Debian不会让您运行脚本。 将文件复制到您的主目录,更改权限,然后运行它:
mkdir ~/VBOXGUEST cp * ~/VBOXGUEST cd ~/VBOXGUEST chmod 755 * sudo ./VBoxLinuxAdditions.run
重启
sudo shutdown -r now
安装Git
sudo apt-get install git
安装Mininet
Mininet允许您虚拟模拟笔记本电脑/ PC上的各种网络接口。 使用Git安装它:
cd ~ # if you are in some other directory git clone git://github.com/mininet/mininet cd mininet git tag # this will list available versions git checkout -b 2.2.1 2.2.1 # replace 2.2.1 with the version you wish to install cd .. mininet/util/install.sh -a # default installation, includes all components, recommended
我建议你安装OpenFlow Wireshark解剖器。 您以后可以安装Wireshark来分析数据包。 OpenFlow Wireshark Dissector帮助Wireshark从OpenFlow数据包中获取尽可能多的信息。
mininet/util/install.sh -h
运行以下命令来检查你的mininet安装:
sudo mn --test pingall
安装Ryu OpenFlow控制器
OpenFlow控制器使用OpenFlow协议在控制层和基础设施层之间进行通信。 此外,它是提供API来开发在应用层(在控制层之上)运行的SDN应用程序的控制器。 有许多OpenFlow控制器。 Ryu OpenFlow控制器是一个使用Python脚本作为应用程序的控制器。 再次,使用Git安装它:
cd ~ git clone git://github.com/osrg/ryu.git
安装Wireshark
sudo apt-get install wireshark
安装支持的Python模块
Debian 8.3默认安装了Python 2.7和3.4。 但是,您需要安装Ryu应用程序(Python脚本)使用的一些Python模块。 您可以使用pip安装Python模块:
cd ~/ryu sudo apt-get install python-dev python-pip python-setuptools sudo pip install .
上面的代码会自动运行位于这个目录下的setup.py,并从Python包索引中获取缺少的Python模块。 该脚本将自动安装所有相关模块。 但是,请执行以下操作以确保您稍后不会丢失任何模块:
sudo pip install webob sudo pip install eventlet sudo pip install paramiko sudo pip install routes
启动
启动mininet使用以下命令模拟3台主机和一台交换机:
sudo mn --topo single,3 --mac --switch ovsk --controller remote
你会看到一个mininet提示符。 这个提示可以用来ping主机,在它们之间发送数据包等。
打开另一个终端窗口来运行Ryu。 在这个例子中,我们将运行一个应用程序(simple_switch_13.py),它将模拟一个简单的第2层交换机,将所有接收到的数据包转发到除接收到的数据包之外的所有端口。
cd ~/ryu PYTHONPATH=. ./bin/ryu-manager ryu/app/simple_switch_13.py
确保您在运行时位于主目录中。
你们都定了 要ping主机并分析数据包传输,请转到下一节。
在本节中,我们将使用mininet将数据包从一台主机发送到另一台主机,并使用tcpdump和Wireshark分析结果传输。
数据包传输的方式正是我们可以在软件定义的网络中控制的。 我们通过编写运行在控制器之上的不同应用程序来完成这项工作。 这些应用构成了SDN控制平面的应用层。
设置拓扑并运行控制应用程序
注意:在前面的章节中,您使用mininet创建了一个拓扑,并启动了一个Ryu应用程序来控制传输。 如果您重新启动或退出其中任何一个,我会重复这些命令来创建拓扑并在此启动Ryu应用程序:
cd ~ sudo mn --topo single,3 --mac --switch ovsk --controller remote
并在一个单独的终端窗口中:
cd ~/ryu PYTHONPATH=. ./bin/ryu-manager ryu/app/simple_switch_13.py
玩包
在mininet提示符下,发出以下命令,为您创建的拓扑中的三台主机中的每台主机打开一个控制台窗口:
mininet> xterm h1 h2 h3
堆叠这些控制台,以便您可以同时看到它们! 然后在h2和h3的xterms中运行tcpdump,一个实用程序打印主机看到的数据包:
tcpdump -XX -n -i h2-eth0 tcpdump -XX -n -i h3-eth0
注意:如果您之前使用过Wireshark,就好像分别在这两台主机的eth0接口上捕获报文。
在创建拓扑时,mininet将以下IP地址分配给三台主机:
h1: 10.0.0.1 h2: 10.0.0.2 h3: 10.0.0.3
从主机1的外壳上ping主机2和主机3,并在每个命令后观察对其他两个控制台的影响:
ping 10.0.0.2 ping 10.0.0.3
尝试ping一个无法访问(不存在的主机),并看到在控制台上的影响:
ping 10.0.0.7
你应该已经观察到ICMP(ping)和ARP(拥有这个IP地址的)协议存在于本节中! 您也可以使用Wireshark而不是tcpdump来完成上述操作。 这是tcpdump的图形化选择。
注意:数据包被转发的方式取决于在Ryu上运行的应用程序。 你可以写一个应用程序来删除所有的数据包。 在这种情况下,你的ping不会对其他两个控制台产生影响。
在本节中,我们将分析在第3节中控制数据包传输的第2层交换机应用程序的简化版本的工作。
工作学习桥(或第2层交换机)
我之前提到,如果你正在阅读本指南,我假设你已经有了基本的网络协议知识(包括第二层交换机,学习桥或以太网交换机的工作),我将会总结不管下面几行。
一个“学习”网桥存储一个与其连接的主机的数据库。 主机由网卡的MAC地址标识,如下所示: ab:cd:ef:12:34:56
(十六进制)。 港口只是由他们的号码标识。 例如,具有4个端口的交换机具有端口1,2,3和4。
如果交换机在端口2上收到一个数据包,它将查看该数据包的目标MAC地址(指向哪个主机)。 然后,它会查看它的数据库,看看它是否知道该主机连接到哪个端口。 如果发现它,它只将该数据包转发到该特定的端口。 但是,如果数据库中没有条目,它会将该数据包扩散到所有端口,如果数据包是发往其的数据包,则主机可以检查它们自己。
同时,交换机查看该数据包的源 MAC地址,并立即知道主机X位于端口2,它将该条目存储在该数据库中。 所以现在你知道了,如果目标主机回复源主机,交换机将不必洪泛回复数据包!
Ryu API Python代码简介
不要直接去simple_switch_13.py,让我们选择一个没有“学习”功能的非常简单的程序。 目前,还没有转发数据库。 下面的程序只是一个简单的第二层交换机,它将接收到的数据包发送到所有端口(泛洪数据包):
from ryu.base import app_manager from ryu.controller import ofp_event from ryu.controller.handler import MAIN_DISPATCHER from ryu.controller.handler import set_ev_cls class L2Switch(app_manager.RyuApp): def __init__(self, *args, **kwargs): super(L2Switch, self).__init__(*args, **kwargs) @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def packet_in_handler(self, ev): msg = ev.msg dp = msg.datapath ofp = dp.ofproto ofp_parser = dp.ofproto_parser actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)] out = ofp_parser.OFPPacketOut( datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port, actions=actions) dp.send_msg(out)
进口
我不会深入研究进口报表。 我们将在分析使用它们的代码时分别讨论这些导入。
基本的应用程序框架
下面的代码是一个完美的Ryu应用程序。 其实你也可以执行它! 但它不会做任何事情:
from ryu.base import app_manager class L2Switch(app_manager.RyuApp): def __init__(self, *args, **kwargs): super(L2Switch, self).__init__(*args, **kwargs)
作为类的参数,我们传递ryu.base.app_manager.RyuApp
导入(在第一行导入)。 从Ryu API手册中, app_manager
类是Ryu应用程序的集中管理。 它加载Ryu应用程序,为它们提供上下文并在Ryu应用程序之间路由消息。
EventOFPPacketIn事件
一个新的方法packet_in_handler
被添加到L2Switch
类。 当Ryu收到一个OpenFlow的packet_in
消息时,这个被调用。 当Ryu收到一个packet_in
消息时,会引发一个ofp_event.EventOFPPacketIn
事件。 set_ev_cls
装饰器告诉Ryu何时应该调用关联的函数packet_in_handler
。
set_ev_cls
装饰器的第一个参数指出了一个调用函数的事件。 正如你所期望的那样,每当发生一个ofp_event.EventOFPPacketIn
事件时,就会调用这个函数。
第二个参数表示当您想允许Ryu处理一个事件时的切换状态。 在Ryu和交换机之间的握手完成之前,您可能想要忽略OpenFlow packet_in
消息。 使用MAIN_DISPATCHER
作为第二个参数意味着这个函数只有在协商完成后才被调用。 MAIN_DISPATCHER
表示交换机的正常状态。 在初始化阶段,交换机处于HANDSHAKE_DISPATCHER
状态!
现在让我们看看函数的主体。 我们将分解成两部分。
msg = ev.msg dp = msg.datapath ofp = dp.ofproto ofp_parser = dp.ofproto_parser
ev.msg
是一个包含接收到的数据包的数据结构。
msg.dp
是表示数据路径(交换机)的数据结构内的对象。
dp.ofproto
和dp.ofproto_parser
是代表Ryu和交换机协商的OpenFlow协议的对象。
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)] out = ofp_parser.OFPPacketOut( datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port, actions=actions) dp.send_msg(out)
OFPActionOutput
类与packet_out
消息一起使用来指定packet_out
中发送数据包的交换机端口。 由于在这个简化的应用程序中没有转发数据库,所以我们把数据包OFPP_FLOOD
到所有端口,所以使用常量OFPP_FLOOD
。
OFPPacketOut
类用于构建packet_out
消息。
通过使用send_msg
类的send_msg
方法,可以将OpenFlow消息对象发送到actions变量中定义的端口。 我再说一遍,在这种情况下,动作是建立的,目的地包括所有端口。
活动
你在上面的代码中反复看到了术语事件。 在事件驱动的编程中,程序的流程由事件控制,事件由系统接收的消息引发(例如,当(OpenFlow启用的)开关接收到 Ryu的packet_in
消息时,会packet_in
。 我们之前曾经讨论过,OpenFlow是一个控制器(Ryu,PC)和基础设施(或交换机)通信的协议。 像 packet_in
这样的 消息 正是使用OpenFlow协议看起来像两个之间的通信!
下一步
你可能想要继续建立你自己的Ryu应用程序。 学习Ryu API(或Python语言,如果你还不熟悉的话)可能是一个好的开始。 祝你好运!
你可能会发现有用的Ryu控制器是Ryuretic。 Ryuretic是一个模块化的,基于SDN的网络应用程序开发框架。 它允许网络运营商直接在OSI模型的不同层次(包括L2,L3,L4和中介层协议)使用分组报头字段。 用户只需选择匹配字段并选择提供的操作来更新OpenFlow交换机。
Ryuretic后端将所有事件作为一个pkt(一个字典对象)呈现给用户,并且通过提供感兴趣的头域(例如,pkt ['srcmac'],pkt ['dstmac'])来检索pkt的内容, pkt ['ethtype'],pkt ['inport'],pkt ['srcip']等)使用来自pkt的信息,用户可以选择匹配哪些字段以及什么动作(fwd,drop,redirect,mirror ,工艺),当发现一场比赛时。
要安装Ryuretic,只需将[files]( https://github.com/Ryuretic/RyureticLabs/tree/master/ryu/ryu/app/Ryuretic )复制到目录/ ryu / ryu / app / Ryuretic。 如果你安装了Ryu,那么你已经有了/ ryu / ryu / app目录。 你只需要创建Ryuretic目录并在那里复制文件。
Ryuretic Labs提供安装说明和一些使用Ryuretic在SDN上实施安全功能的使用案例。 它还提供了一个Mininet测试平台,用于在SDN-Hub提供的虚拟机上测试您的网络应用程序。