了解 Ryu OpenFlow 控制器、mininet、WireShark 和 tcpdump



我是OpenFlow和SDN的新手。我需要帮助在 Ubuntu 或 Debian 机器上设置 Ryu OpenFlow 控制器,并了解基本的 Ryu 应用程序。

注意:这个问题已经有了答案。

这可能是我在Stack Overflow上写过的最长的文章之一。我一直在学习OpenFlow,SDN和Ryu,并希望在这里为初学者记录我的知识。如果需要,请更正/编辑我的帖子。

本简短指南假定您已经了解计算机网络和主要网络协议。本指南将帮助您从系统设置开始使用 OpenFlow。

1. 什么是OpenFlow和SDN?

请阅读SDN/OpenFlow |流量可。

延伸阅读:Scott Shenker 的《网络的未来和协议的过去》和《软件定义网络》,IEEE INFOCOM 2009。

开始之前:

基础架构层包括网络核心内的路由器和交换机。

控制层包括运行OpenFlow控制器的PC以及控制器本身。

应用程序层包括在该控制器上运行的应用程序。在Ryu中,这些应用程序是用Python编写的。

OpenFlow 是一种基础设施和控制层交互的协议。OpenFlow不提供自己的API。它是一种开源协议,由开发支持 OpenFlow 的交换机的供应商和编写控制器的开发人员(如 Ryu)使用。API 由控制器提供。

2. 在 Debian 8 上设置 Ryu OpenFlow 控制器

先决条件

您需要互联网接入。如果您在虚拟机中运行 Debian,请发出以下命令以通过 NAT 自动配置您的以太网接口:

su  
dhclient eth0

启用须藤

Debian 默认不附带 sudo。您稍后将使用的一些 Ryu 应用程序需要 sudo。您可以安装 sudo 并将自己添加到 sudo'ers 列表中,如下所示:

su
apt-get install sudo # you might need to do apt-get update first!
visudo

找到显示 %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允许您虚拟模拟笔记本电脑/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 Dissector。您可以稍后安装 Wireshark 来分析数据包。OpenFlow Wireshark Dissector帮助Wireshark从OpenFlow数据包中获取尽可能多的信息。

mininet/util/install.sh -h

运行以下命令以检查您的迷你网安装:

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

您将看到一个迷你网提示。此提示可用于 ping 主机、在它们之间发送数据包等。

打开另一个终端窗口以运行 Ryu。在此示例中,我们将运行一个应用程序 (simple_switch_13.py),该应用程序将模拟一个简单的第 2 层交换机,该交换机会将所有收到的数据包转发到除接收端口之外的所有端口。

cd ~/ryu  
PYTHONPATH=. ./bin/ryu-manager ryu/app/simple_switch_13.py

运行此命令时,请确保您位于主目录中。

一切就绪。要 ping 主机并分析数据包传输,请转到下一部分。

3. 尝试使用Wireshark和tcpdump

在本节中,我们将使用 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 的 shell 中,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 不会对其他两个控制台产生任何影响。

4. 了解基本的第 2 层交换机应用

在本节中,我们将分析第 2 层交换机应用程序的简化版本的工作,该应用程序控制第 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,不如让我们选择一个非常简单的程序,没有"学习"功能。目前,没有转发数据库。下面的程序只是一个简单的第 2 层交换机,它将接收到的数据包传输到所有端口(泛洪数据包):

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 应用程序之间路由消息。

事件OFPPacketIn Event

新方法packet_in_handler将添加到类L2Switch。当 Ryu 收到 OpenFlowpacket_in消息时,将调用此值。当 Ryu 收到packet_in消息时,将引发ofp_event.EventOFPPacketIn事件。set_ev_cls装饰器告诉 Ryu 何时应调用关联的函数packet_in_handler

set_ev_cls装饰器的第一个参数指示使函数调用的事件。正如您所期望的那样,每次引发ofp_event.EventOFPPacketIn事件时,都会调用此函数。

第二个参数指示您希望允许 Ryu 处理事件时交换机的状态。您可能希望在Ryu和交换机之间的握手完成之前忽略OpenFlowpacket_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.ofprotodp.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消息一起使用,以指定要从中发送数据包的交换机端口。由于这个简化的应用程序中没有转发数据库,因此我们将数据包泛洪到所有端口,因此使用常量OFPP_FLOOD

OFPPacketOut类用于生成packet_out消息。

通过使用类datapathsend_msg方法,您可以将 OpenFlow 消息对象发送到 actions 变量中定义的端口。我再说一遍,在这种情况下,构建的操作使目标包括所有端口。

事件

您在上面的代码中反复看到术语事件。在事件驱动编程中,程序的流程由事件控制,事件由系统接收的消息引发(例如 当 Ryu 从(启用 OpenFlow)开关接收到packet_in消息时,会引发EventOFPPacketIn)。我们之前讨论过OpenFlow是控制器(Ryu,PC)和基础设施(或交换机)通信的协议。像这样的消息packet_in正是使用OpenFlow协议两者之间的通信的样子!

后续步骤

您可能希望继续构建自己的 Ryu 应用程序。学习Ryu API(或Python语言,如果你还不熟悉它)可能是一个很好的起点。祝你好运!

您可能会发现使用Ryu控制器有用的东西是Ryuretic。Ryuretic是一个模块化的,基于SDN的网络应用程序开发框架。它允许网络运营商直接使用 OSI 模型各个级别的数据包标头字段,包括 L2、L3、L4 和填充层协议。用户只需选择匹配字段并选择提供的操作即可更新 OpenFlow 开关。

Ryuretic 后端将所有事件作为 pkt(字典对象)呈现给用户,并且通过提供感兴趣的标头字段来检索 pkt 的内容(例如,pkt['srcmac']、pkt['dstmac']、pkt['ethtype']、pkt['inport']、pkt['srcip'] 等)。使用 pkt 中的信息,用户可以选择要匹配的字段以及在找到匹配项时要执行的操作(fwd、丢弃、重定向、镜像、制作)。

要安装 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 提供的 VM 上测试网络应用程序。

最新更新