|
|
|
@ -6,23 +6,587 @@
|
|
|
|
|
\subsection{实验目的}
|
|
|
|
|
\label{subsec:c:sdn-ob:s:sdn_object}
|
|
|
|
|
|
|
|
|
|
本实验的主要目的是让学生了解SDN的概念及三层结构原理,
|
|
|
|
|
掌握OpenFlow协议格式、内容、工作流程及对应功能作用。
|
|
|
|
|
掌握SDN控制器北向API使用方法,可通过API编程获取和设置交换机数据。
|
|
|
|
|
|
|
|
|
|
\subsection{实验内容}
|
|
|
|
|
\label{subsec:c:sdn-ob:s:sdn_content}
|
|
|
|
|
|
|
|
|
|
使用可编程网络平台及SDN交换机示例框架代码,完成OpenFlow协议的部分功能逻辑。
|
|
|
|
|
验证并分析SDN交换机的工作原理与处理流程。主要完成以下内容:
|
|
|
|
|
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\item \textbf{阅读协议:}阅读OpenFlow 1.3版本协议白皮书,
|
|
|
|
|
掌握其协议内容及对应功能;
|
|
|
|
|
\item \textbf{设计实现协议功能:}基于SDN交换机示例框架代码,
|
|
|
|
|
选择开发OpenFlow协议的部分功能,完成逻辑设计与实现;
|
|
|
|
|
\item \textbf{验证交换机功能:}运行自己的SDN交换机,跟控制器建立连接,
|
|
|
|
|
在控制器查询其工作状态与相关协议功能展示。
|
|
|
|
|
如交换机基本信息描述、交换机流表状态、
|
|
|
|
|
交换机端口状态及计数统计、网络拓扑展示效果;
|
|
|
|
|
\item \textbf{检验流表:}验证SDN交换机连接主机间的通信功能,
|
|
|
|
|
并观察流表内容及变化情况;
|
|
|
|
|
\item \textbf{REST API应用:}使用实验提供的北向REST~API接口查询控制器,
|
|
|
|
|
获取或设置交换机的不同功能数据;
|
|
|
|
|
\item \textbf{定义流表:}使用REST API接口修改流表内容,
|
|
|
|
|
观察主机的通信情况是否受到影响;
|
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
|
|
\subsection{实验原理、方法和手段}
|
|
|
|
|
\label{subsec:c:sdn-ob:s:sdn_principle}
|
|
|
|
|
|
|
|
|
|
\subsection{SDN交换机工作原理}
|
|
|
|
|
SDN即Software Defined Network(软件定义网络),
|
|
|
|
|
是一种新型网络创新架构,用于解决传统网络架构中对于网络虚拟化、
|
|
|
|
|
各类自动化部署以及新型网络协议的问题。
|
|
|
|
|
|
|
|
|
|
SDN将传统的紧耦合网络设备被拆分成了应用、控制、转发三层,
|
|
|
|
|
其中应用和控制层面能够控制网络中数据的流向以及协议控制,
|
|
|
|
|
而底层的网络设备被抽象为了可自定义的转发逻辑实体,
|
|
|
|
|
可被上层应用定义为不同类型的转发设备。
|
|
|
|
|
|
|
|
|
|
在应用层,用户可通过通用、简单的API获取网络信息,
|
|
|
|
|
并可修改转发设备的工作逻辑,达到动态改变网络架构的目的。
|
|
|
|
|
|
|
|
|
|
\subsection{SDN交换机分组处理流程}
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\item \textbf{启动协议通道:}
|
|
|
|
|
SDN交换机运行OpenFlow协议代理程序与上层控制器建立通信连接。
|
|
|
|
|
交换机解析处理OpenFlow协议,
|
|
|
|
|
根据协议要求完成协议功能的相关数据收集和配置功能,
|
|
|
|
|
构造相应的OpenFlow协议应答控制器。
|
|
|
|
|
|
|
|
|
|
\item \textbf{建立连接:}OpenFlow协议代理运行时,
|
|
|
|
|
交换机首先和控制器建立连接,
|
|
|
|
|
并发送OFP\_HELLO消息用以确认双方都支持的OFP协议版本信息;
|
|
|
|
|
\item \textbf{查询或设置数据:}
|
|
|
|
|
控制器通过OpenFlow的具体消息协议查询或设置交换机其他相关功能的数据,
|
|
|
|
|
如OFPT\_HELLO、OFPT\_ECHO\_REQUEST、OFPT\_PACKET\_IN、OFPT\_PACKET\_OUT、
|
|
|
|
|
OFPT\_FLOW\_MOD、OFPT\_PORT\_MOD、OFPMP\_DESC、OFPMP\_FLOW、OFPMP\_PORT\_STATS等;
|
|
|
|
|
\item \textbf{处理转发分组:}当交换机接收到一个数据转发分组时,
|
|
|
|
|
提取分组数据中的相关字段组成查表关键字,然后在本地进行流表匹配。
|
|
|
|
|
如果匹配成功,则根据流表的动作处理该分组,如从其他端口转发出去;
|
|
|
|
|
如果匹配不成功,则会命中默认动作,将分组打包送到控制器;
|
|
|
|
|
\item \textbf{PACKET\_IN分组上传:}交换机查表不命中或是接收到链路探测报文,
|
|
|
|
|
则将该数据封装在OpenFlow的PACKET\_IN消息中,上传给控制器;
|
|
|
|
|
\item \textbf{PACKET\_OUT分组下发:}通过PACKET\_IN上传的分组,
|
|
|
|
|
经过控制器分析处理后,会将其封装在OpenFlow协议的PACKET\_OUT消息中,
|
|
|
|
|
并携带输出端口信息下发到交换机。交换机接收到该消息数据后,
|
|
|
|
|
根据输出信息指示,将该分组从指定端口输出。
|
|
|
|
|
通过PACKET\_OUT发送的分组数据还包括链路探测协议报文。
|
|
|
|
|
\item \textbf{FLOW\_MOD消息处理:}
|
|
|
|
|
控制器通过下发FLOW\_MOD消息给交换机的流表设置转发表项内容,
|
|
|
|
|
FLOW\_MOD消息中包括分组特征元组信息和动作执行列表。
|
|
|
|
|
特征元组通常包括常用的MAC信息、帧类型和五元组信息等,
|
|
|
|
|
动作通常包括输出端口或丢弃信息等;
|
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
|
|
\subsection{实验条件}
|
|
|
|
|
\label{subsec:c:sdn-ob:s:sdn_requirement}
|
|
|
|
|
|
|
|
|
|
\begin{itemize}
|
|
|
|
|
\item 可编程网络平台一个,交换测试主机两台,
|
|
|
|
|
SDN控制器(安装SDN控制器软件Floodlight)一台。
|
|
|
|
|
网络配置及连接拓扑如图\ref{fig:c:sdn-ob_sdn-topo}所示;
|
|
|
|
|
\item 串口线一根,网线三根;
|
|
|
|
|
\item SDN交换机框架开发源代码、流表配置Python脚本。
|
|
|
|
|
\end{itemize}
|
|
|
|
|
|
|
|
|
|
\begin{figure}[!ht]
|
|
|
|
|
\centering
|
|
|
|
|
\includegraphics[width=9cm]{sdn-topo}
|
|
|
|
|
\caption{OpenFlow交换机实验拓扑图}
|
|
|
|
|
\label{fig:c:sdn-ob_sdn-topo}
|
|
|
|
|
\end{figure}
|
|
|
|
|
|
|
|
|
|
\subsection{实验步骤}
|
|
|
|
|
\label{subsec:c:sdn-ob:s:sdn_procedure}
|
|
|
|
|
|
|
|
|
|
\subsubsection{编译运行SDN交换机,验证交换机基本功能;}
|
|
|
|
|
|
|
|
|
|
请参考附件\ref{app:openbox}:《可编程网络平台-操作手册》完成。
|
|
|
|
|
|
|
|
|
|
\subsubsection{基于SDN交换机源码,选择实现自己的协议功能;}
|
|
|
|
|
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\item 修改源代码
|
|
|
|
|
\begin{code}[c]
|
|
|
|
|
enum ofperr handle_openflow_callback(struct ofp_buffer *ofpbuf,int len)
|
|
|
|
|
{
|
|
|
|
|
int oftype = ofpbuf->header.type;
|
|
|
|
|
|
|
|
|
|
SHOW_FUN(0);
|
|
|
|
|
LOG_DBG("ofpbuf->header.type=%d\n",ofpbuf->header.type);
|
|
|
|
|
switch(oftype)
|
|
|
|
|
{
|
|
|
|
|
case OFPT_HELLO:
|
|
|
|
|
/*用户不实现该类消息处理,则直接break,函数返回CONTINUE,
|
|
|
|
|
*由系统库完成后续处理;*/
|
|
|
|
|
break;
|
|
|
|
|
case OFPT_PACKET_OUT:
|
|
|
|
|
/*若用户想实现该消息的处理,则在此处完成对消息的功能逻辑,
|
|
|
|
|
*然后直接返回HANDLE,表示已经处理,库函数直接返回*/
|
|
|
|
|
//TO DO 用户在些添加处理逻辑,完成该消息功能
|
|
|
|
|
return HANDLE;
|
|
|
|
|
//可再增加其他OpenFlow协议的消息类型
|
|
|
|
|
}
|
|
|
|
|
return CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
\end{code}
|
|
|
|
|
用户可以根据自己能力选择实现OpenFlow协议的部分消息功能,
|
|
|
|
|
一旦处理了该消息,一定要返回HANDLE,否则直接break即可。
|
|
|
|
|
\item 编译源代码
|
|
|
|
|
\begin{code}[console]
|
|
|
|
|
root@HNXS-FAST:/home/hnxs/sdn# make
|
|
|
|
|
gcc –o user_openflow –l reg –l ua –l rule –l ofp -lpthread
|
|
|
|
|
root@HNXS-FAST:/home/hnxs/sdn# ls
|
|
|
|
|
main_openflow.c Makefile user_openflow
|
|
|
|
|
root@HNXS-FAST:/home/hnxs/sdn#
|
|
|
|
|
\end{code}
|
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
|
|
\subsubsection{运行修改后的交换机,再次验证SDN交换机的功能;}
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\item 运行SDN交换机,交换机正常工作后输出如下;
|
|
|
|
|
\begin{code}[console]
|
|
|
|
|
root@HNXS-FAST:/home/hnxs/sdn# ./ user_openflow -4 192.168.1.3 -i obx0,obx1,obx2,obx3
|
|
|
|
|
fastU->REG Version:20180827,OpenBox HW Version:2030200722
|
|
|
|
|
port_name:eth0,port:0
|
|
|
|
|
port_name:obx0,port:0
|
|
|
|
|
xofp uses obsolete (PF_INET,SOCK_PACKET)
|
|
|
|
|
port_name:obx1,port:1
|
|
|
|
|
port_name:obx2,port:2
|
|
|
|
|
port_name:obx3,port:3
|
|
|
|
|
fastU->librule version:20181015,Default Action:0x40000080
|
|
|
|
|
xofp)Connect to SDN Controller [ 192.168.1.3:6653 ] OK!
|
|
|
|
|
0_nms_of13)DELETE ALL RULE!
|
|
|
|
|
eth0 ADD!
|
|
|
|
|
obx0 ADD!
|
|
|
|
|
obx1 ADD!
|
|
|
|
|
obx2 ADD!
|
|
|
|
|
obx0(0x29008) Start...
|
|
|
|
|
obx2(0x2e100) Start...
|
|
|
|
|
obx3(0x30958) Start...
|
|
|
|
|
obx1(0x2b890) Start...
|
|
|
|
|
obx3 ADD!
|
|
|
|
|
\end{code}
|
|
|
|
|
|
|
|
|
|
\item 查看控制器界面基本信息,
|
|
|
|
|
在浏览器打开控制器WEB网站\url{http://192.168.1.3/ui/index.html},
|
|
|
|
|
控制界面如图\ref{fig:c:sdn-ob_sdn-switch}所示:
|
|
|
|
|
\begin{figure}[!htp]
|
|
|
|
|
\centering
|
|
|
|
|
\includegraphics[width=14cm]{sdn-switch}
|
|
|
|
|
\caption{SDN交换机信息}
|
|
|
|
|
\label{fig:c:sdn-ob_sdn-switch}
|
|
|
|
|
\end{figure}
|
|
|
|
|
|
|
|
|
|
\item 查看连接测试主机信息,
|
|
|
|
|
SDN主机及连接信息如图\ref{fig:c:sdn-ob_sdn-host}所示:
|
|
|
|
|
\begin{figure}[!htp]
|
|
|
|
|
\centering
|
|
|
|
|
\includegraphics[width=14cm]{sdn-host}
|
|
|
|
|
\caption{SDN主机信息}
|
|
|
|
|
\label{fig:c:sdn-ob_sdn-host}
|
|
|
|
|
\end{figure}
|
|
|
|
|
|
|
|
|
|
\item 查看端口状态与计数信息与流表信息,
|
|
|
|
|
端口状态与流表计数信息如图\ref{fig:c:sdn-ob_port-flowtable}所示:
|
|
|
|
|
\begin{figure}[!htp]
|
|
|
|
|
\centering
|
|
|
|
|
\includegraphics[width=14cm]{port-flowtable}
|
|
|
|
|
\caption{端口状态与流表计数信息}
|
|
|
|
|
\label{fig:c:sdn-ob_port-flowtable}
|
|
|
|
|
\end{figure}
|
|
|
|
|
|
|
|
|
|
\item 查看网络拓扑信息,如图\ref{fig:c:sdn-ob_sdn-test-topo}所示:
|
|
|
|
|
\begin{figure}[!htp]
|
|
|
|
|
\centering
|
|
|
|
|
\includegraphics[width=14cm]{sdn-test-topo}
|
|
|
|
|
\caption{SDN网络拓扑信息}
|
|
|
|
|
\label{fig:c:sdn-ob_sdn-test-topo}
|
|
|
|
|
\end{figure}
|
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
|
|
\subsubsection{在测试主机ping的前后,分别观察流表变化;}
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\item ping之前的流表信息(使用REST API方式获取其json数据),
|
|
|
|
|
如图\ref{fig:c:sdn-ob_empty-flowtable}所示:
|
|
|
|
|
\begin{figure}[!htp]
|
|
|
|
|
\centering
|
|
|
|
|
\includegraphics[width=14cm]{empty-flowtable}
|
|
|
|
|
\caption{空流表信息}
|
|
|
|
|
\label{fig:c:sdn-ob_empty-flowtable}
|
|
|
|
|
\end{figure}
|
|
|
|
|
|
|
|
|
|
\item ping之后的流表信息,如图\ref{fig:c:sdn-ob_flowtable-ping}所示:
|
|
|
|
|
\begin{figure}[!htp]
|
|
|
|
|
\centering
|
|
|
|
|
\includegraphics[width=14cm]{flowtable-ping}
|
|
|
|
|
\caption{ping通后流表信息}
|
|
|
|
|
\label{fig:c:sdn-ob_flowtable-ping}
|
|
|
|
|
\end{figure}
|
|
|
|
|
Ping通之后在SDN交换机的流表里多了4条转发流表,
|
|
|
|
|
分别是两个方向的ARP应答报文转发表和两个方向的IP报文转发表
|
|
|
|
|
(具体内容在后面的REST~API数据中查验)。
|
|
|
|
|
由此可以说明:控制器向SDN交换机注入了四条转发流表,才让两边的主机ping通了。
|
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
|
|
\subsubsection{使用REST API接口查询交换机的相关功能数据;}
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\item 查询交换机基本信息
|
|
|
|
|
\begin{code}[console]
|
|
|
|
|
# curl http://192.168.1.3:8080/wm/core/switch/\
|
|
|
|
|
00:00:00:0a:00:00:08:01/desc/json
|
|
|
|
|
\end{code}
|
|
|
|
|
\begin{code}[json]
|
|
|
|
|
{
|
|
|
|
|
"desc": {
|
|
|
|
|
"version": "OF_13",
|
|
|
|
|
"manufacturer_description": "HuNan XinShi NetWork",
|
|
|
|
|
"hardware_description": "OpenBox HW 2017",
|
|
|
|
|
"software_description": "OpenBox Driver 1.0.0",
|
|
|
|
|
"serial_number": "None",
|
|
|
|
|
"datapath_description": "None"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
\end{code}
|
|
|
|
|
\item 查询端口计数信息
|
|
|
|
|
\begin{code}[console]
|
|
|
|
|
# curl http://192.168.1.3:8080/wm/core/switch/\
|
|
|
|
|
00:00:00:0a:00:00:08:01/port/json
|
|
|
|
|
\end{code}
|
|
|
|
|
\begin{code}[json]
|
|
|
|
|
{
|
|
|
|
|
"port_reply": [{
|
|
|
|
|
"version": "OF_13",
|
|
|
|
|
"port": [{
|
|
|
|
|
"port_number": "local",
|
|
|
|
|
"receive_packets": "10957",
|
|
|
|
|
"transmit_packets": "1180",
|
|
|
|
|
"receive_bytes": "592738",
|
|
|
|
|
"transmit_bytes": "143898",
|
|
|
|
|
"receive_dropped": "0",
|
|
|
|
|
"transmit_dropped": "0",
|
|
|
|
|
"receive_errors": "0",
|
|
|
|
|
"transmit_errors": "0",
|
|
|
|
|
"receive_frame_errors": "0",
|
|
|
|
|
"receive_overrun_errors": "0",
|
|
|
|
|
"receive_CRC_errors": "0",
|
|
|
|
|
"collisions": "0",
|
|
|
|
|
"duration_sec": "4294966827",
|
|
|
|
|
"duration_nsec": "573987"
|
|
|
|
|
}, {
|
|
|
|
|
"port_number": "1",
|
|
|
|
|
"receive_packets": "86",
|
|
|
|
|
"transmit_packets": "205",
|
|
|
|
|
"receive_bytes": "11427",
|
|
|
|
|
"transmit_bytes": "22632",
|
|
|
|
|
"receive_dropped": "0",
|
|
|
|
|
"transmit_dropped": "0",
|
|
|
|
|
"receive_errors": "0",
|
|
|
|
|
"transmit_errors": "0",
|
|
|
|
|
"receive_frame_errors": "0",
|
|
|
|
|
"receive_overrun_errors": "0",
|
|
|
|
|
"receive_CRC_errors": "0",
|
|
|
|
|
"collisions": "0",
|
|
|
|
|
"duration_sec": "4294966827",
|
|
|
|
|
"duration_nsec": "573991"
|
|
|
|
|
}, {
|
|
|
|
|
"port_number": "2",
|
|
|
|
|
"receive_packets": "0",
|
|
|
|
|
"transmit_packets": "0",
|
|
|
|
|
"receive_bytes": "0",
|
|
|
|
|
"transmit_bytes": "0",
|
|
|
|
|
"receive_dropped": "0",
|
|
|
|
|
"transmit_dropped": "0",
|
|
|
|
|
"receive_errors": "0",
|
|
|
|
|
"transmit_errors": "0",
|
|
|
|
|
"receive_frame_errors": "0",
|
|
|
|
|
"receive_overrun_errors": "0",
|
|
|
|
|
"receive_CRC_errors": "0",
|
|
|
|
|
"collisions": "0",
|
|
|
|
|
"duration_sec": "4294966827",
|
|
|
|
|
"duration_nsec": "573992"
|
|
|
|
|
}, {
|
|
|
|
|
"port_number": "3",
|
|
|
|
|
"receive_packets": "616",
|
|
|
|
|
"transmit_packets": "220",
|
|
|
|
|
"receive_bytes": "56948",
|
|
|
|
|
"transmit_bytes": "24659",
|
|
|
|
|
"receive_dropped": "0",
|
|
|
|
|
"transmit_dropped": "0",
|
|
|
|
|
"receive_errors": "0",
|
|
|
|
|
"transmit_errors": "0",
|
|
|
|
|
"receive_frame_errors": "0",
|
|
|
|
|
"receive_overrun_errors": "0",
|
|
|
|
|
"receive_CRC_errors": "0",
|
|
|
|
|
"collisions": "0",
|
|
|
|
|
"duration_sec": "4294966827",
|
|
|
|
|
"duration_nsec": "573994"
|
|
|
|
|
}, {
|
|
|
|
|
"port_number": "4",
|
|
|
|
|
"receive_packets": "0",
|
|
|
|
|
"transmit_packets": "0",
|
|
|
|
|
"receive_bytes": "0",
|
|
|
|
|
"transmit_bytes": "0",
|
|
|
|
|
"receive_dropped": "0",
|
|
|
|
|
"transmit_dropped": "0",
|
|
|
|
|
"receive_errors": "0",
|
|
|
|
|
"transmit_errors": "0",
|
|
|
|
|
"receive_frame_errors": "0",
|
|
|
|
|
"receive_overrun_errors": "0",
|
|
|
|
|
"receive_CRC_errors": "0",
|
|
|
|
|
"collisions": "0",
|
|
|
|
|
"duration_sec": "4294966827",
|
|
|
|
|
"duration_nsec": "573995"
|
|
|
|
|
}]
|
|
|
|
|
}]
|
|
|
|
|
}
|
|
|
|
|
\end{code}
|
|
|
|
|
\item 查询交换机流表信息
|
|
|
|
|
\begin{code}[console]
|
|
|
|
|
# curl http://192.168.1.3:8080/wm/core/switch/\
|
|
|
|
|
00:00:00:0a:00:00:08:01/flow/json
|
|
|
|
|
\end{code}
|
|
|
|
|
\begin{code}[json]
|
|
|
|
|
{
|
|
|
|
|
"flows": [{
|
|
|
|
|
"version": "OF_13",
|
|
|
|
|
"cookie": "9007199254740992",
|
|
|
|
|
"table_id": "0x0",
|
|
|
|
|
"packet_count": "5",
|
|
|
|
|
"byte_count": "571392",
|
|
|
|
|
"duration_sec": "0",
|
|
|
|
|
"duration_nsec": "0",
|
|
|
|
|
"priority": "1",
|
|
|
|
|
"idle_timeout_s": "5",
|
|
|
|
|
"hard_timeout_s": "0",
|
|
|
|
|
"flags": [],
|
|
|
|
|
"match": {
|
|
|
|
|
"in_port": "1",
|
|
|
|
|
"eth_dst": "b8:27:eb:c1:d1:39",
|
|
|
|
|
"eth_src": "b8:27:eb:d8:83:20",
|
|
|
|
|
"eth_type": "0x806"
|
|
|
|
|
},
|
|
|
|
|
"instructions": {
|
|
|
|
|
"instruction_apply_actions": {
|
|
|
|
|
"actions": "output=3"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, {
|
|
|
|
|
"version": "OF_13",
|
|
|
|
|
"cookie": "9007199271518208",
|
|
|
|
|
"table_id": "0x0",
|
|
|
|
|
"packet_count": "162",
|
|
|
|
|
"byte_count": "571400",
|
|
|
|
|
"duration_sec": "0",
|
|
|
|
|
"duration_nsec": "0",
|
|
|
|
|
"priority": "1",
|
|
|
|
|
"idle_timeout_s": "5",
|
|
|
|
|
"hard_timeout_s": "0",
|
|
|
|
|
"flags": [],
|
|
|
|
|
"match": {
|
|
|
|
|
"in_port": "3",
|
|
|
|
|
"eth_dst": "b8:27:eb:d8:83:20",
|
|
|
|
|
"eth_src": "b8:27:eb:c1:d1:39",
|
|
|
|
|
"eth_type": "0x800",
|
|
|
|
|
"ipv4_src": "192.168.2.119",
|
|
|
|
|
"ipv4_dst": "192.168.2.111"
|
|
|
|
|
},
|
|
|
|
|
"instructions": {
|
|
|
|
|
"instruction_apply_actions": {
|
|
|
|
|
"actions": "output=1"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, {
|
|
|
|
|
"version": "OF_13",
|
|
|
|
|
"cookie": "9007199288295424",
|
|
|
|
|
"table_id": "0x0",
|
|
|
|
|
"packet_count": "161",
|
|
|
|
|
"byte_count": "571408",
|
|
|
|
|
"duration_sec": "0",
|
|
|
|
|
"duration_nsec": "0",
|
|
|
|
|
"priority": "1",
|
|
|
|
|
"idle_timeout_s": "5",
|
|
|
|
|
"hard_timeout_s": "0",
|
|
|
|
|
"flags": [],
|
|
|
|
|
"match": {
|
|
|
|
|
"in_port": "1",
|
|
|
|
|
"eth_dst": "b8:27:eb:c1:d1:39",
|
|
|
|
|
"eth_src": "b8:27:eb:d8:83:20",
|
|
|
|
|
"eth_type": "0x800",
|
|
|
|
|
"ipv4_src": "192.168.2.111",
|
|
|
|
|
"ipv4_dst": "192.168.2.119"
|
|
|
|
|
},
|
|
|
|
|
"instructions": {
|
|
|
|
|
"instruction_apply_actions": {
|
|
|
|
|
"actions": "output=3"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, {
|
|
|
|
|
"version": "OF_13",
|
|
|
|
|
"cookie": "9007199305072640",
|
|
|
|
|
"table_id": "0x0",
|
|
|
|
|
"packet_count": "2",
|
|
|
|
|
"byte_count": "571416",
|
|
|
|
|
"duration_sec": "0",
|
|
|
|
|
"duration_nsec": "0",
|
|
|
|
|
"priority": "1",
|
|
|
|
|
"idle_timeout_s": "5",
|
|
|
|
|
"hard_timeout_s": "0",
|
|
|
|
|
"flags": [],
|
|
|
|
|
"match": {
|
|
|
|
|
"in_port": "3",
|
|
|
|
|
"eth_dst": "b8:27:eb:d8:83:20",
|
|
|
|
|
"eth_src": "b8:27:eb:c1:d1:39",
|
|
|
|
|
"eth_type": "0x806"
|
|
|
|
|
},
|
|
|
|
|
"instructions": {
|
|
|
|
|
"instruction_apply_actions": {
|
|
|
|
|
"actions": "output=1"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}]
|
|
|
|
|
}
|
|
|
|
|
\end{code}
|
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
|
|
\subsubsection*{修改Python脚本,手动配置流表,观察测试主机的通信变化;}
|
|
|
|
|
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\item 修改流表脚本,使其转发端口错误
|
|
|
|
|
\begin{code}[console]
|
|
|
|
|
#vim openflow_flow-test.py
|
|
|
|
|
\end{code}
|
|
|
|
|
\begin{code}[python]
|
|
|
|
|
import httplib
|
|
|
|
|
import json
|
|
|
|
|
|
|
|
|
|
class StaticFlowPusher(object):
|
|
|
|
|
def __init__(self, server):
|
|
|
|
|
self.server = server
|
|
|
|
|
|
|
|
|
|
def get(self, data):
|
|
|
|
|
ret = self.rest_call({}, 'GET')
|
|
|
|
|
return json.loads(ret[2])
|
|
|
|
|
|
|
|
|
|
def set(self, data):
|
|
|
|
|
ret = self.rest_call(data, 'POST')
|
|
|
|
|
return ret[0] == 200
|
|
|
|
|
|
|
|
|
|
def remove(self, objtype, data):
|
|
|
|
|
ret = self.rest_call(data, 'DELETE')
|
|
|
|
|
return ret[0] == 200
|
|
|
|
|
|
|
|
|
|
def rest_call(self, data, action):
|
|
|
|
|
path = '/wm/staticflowpusher/json'
|
|
|
|
|
headers = {
|
|
|
|
|
'Content-type': 'application/json',
|
|
|
|
|
'Accept': 'application/json',
|
|
|
|
|
}
|
|
|
|
|
body = json.dumps(data)
|
|
|
|
|
conn = httplib.HTTPConnection(self.server, 8080)
|
|
|
|
|
conn.request(action, path, body, headers)
|
|
|
|
|
response = conn.getresponse()
|
|
|
|
|
ret = (response.status, response.reason, response.read())
|
|
|
|
|
print ret
|
|
|
|
|
conn.close()
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
pusher = StaticFlowPusher('192.168.1.3')
|
|
|
|
|
|
|
|
|
|
flowbe0 = {
|
|
|
|
|
'switch':"00:00:00:0a:00:00:08:01",
|
|
|
|
|
"table":"0",
|
|
|
|
|
"name":"flow-0",
|
|
|
|
|
"cookie":"60",
|
|
|
|
|
"priority":"1",
|
|
|
|
|
"active":"true",
|
|
|
|
|
"eth_dst":" b8:27:eb:c1:d1:39", #dmac
|
|
|
|
|
"eth_src":" b8:27:eb:d8:83:20", #smac
|
|
|
|
|
"eth_type":"0x800", #type
|
|
|
|
|
#"ip_proto":"0x11", #proto
|
|
|
|
|
"in_port":"1", #inport
|
|
|
|
|
"ipv4_src":"192.168.2.111", #sip
|
|
|
|
|
"ipv4_dst":"192.168.2.119", #dip
|
|
|
|
|
#"tp_src":"50001", #sport
|
|
|
|
|
#"tp_dst":"50001", #dport
|
|
|
|
|
"actions":"output=2" #正确值应该为3
|
|
|
|
|
}
|
|
|
|
|
flowbe1 = {
|
|
|
|
|
'switch':"00:00:00:0a:00:00:08:01",
|
|
|
|
|
"table":"1",
|
|
|
|
|
"name":"flow-1",
|
|
|
|
|
"cookie":"61",
|
|
|
|
|
"priority":"1",
|
|
|
|
|
"active":"true",
|
|
|
|
|
"eth_dst":"b8:27:eb:d8:83:20", #dmac
|
|
|
|
|
"eth_src":"b8:27:eb:c1:d1:39", #smac
|
|
|
|
|
"eth_type":"0x800", #type
|
|
|
|
|
#"ip_proto":"0x11", #proto
|
|
|
|
|
"in_port":"3", #inport
|
|
|
|
|
"ipv4_src":"192.168.2.119", #sip
|
|
|
|
|
"ipv4_dst":"192.168.2.111", #dip
|
|
|
|
|
#"tp_src":"50001", #sport
|
|
|
|
|
#"tp_dst":"50001", #dport
|
|
|
|
|
"actions":"output=2" #正确值应该为1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pusher.set(flowbe0)
|
|
|
|
|
pusher.set(flowbe1)
|
|
|
|
|
\end{code}
|
|
|
|
|
|
|
|
|
|
脚本执行命令如下:
|
|
|
|
|
\begin{code}[console]
|
|
|
|
|
# python openflow_flow-test.py
|
|
|
|
|
(200, 'OK', '{"status" : "Entry pushed"}')
|
|
|
|
|
(200, 'OK', '{"status" : "Entry pushed"}')
|
|
|
|
|
\end{code}
|
|
|
|
|
|
|
|
|
|
脚本执行成功,两条流表添加成功,在测试主机两边进行ping测试,
|
|
|
|
|
是否发现已经ping不通了?
|
|
|
|
|
\item 修改流表脚本,使其转发端口正确,再次验证;
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\item 两种动作分别修改为:1进3出和3进1出。
|
|
|
|
|
添加流表后,再重新ping测试,是否发现又可以ping通了?
|
|
|
|
|
\item 由此说明:对于SDN交换机,
|
|
|
|
|
可以通过用户修改流表的方式来定义某一条具体流的转发行为。
|
|
|
|
|
\end{enumerate}
|
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
|
|
\subsection{思考题}
|
|
|
|
|
\label{subsec:c:sdn-ob:s:sdn_rethink}
|
|
|
|
|
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\item WEB界面上显示的转发流表是如何生成的?分析其生成流程;
|
|
|
|
|
\item 测试主机第一次ping通的数据处理流程与第二次ping通的数据处理流程有何不同?
|
|
|
|
|
\item 控制器界面的拓扑图是如何生成的?需要哪些数据?
|
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
|
|
\subsection{注意事项及有关说明}
|
|
|
|
|
\label{subsec:c:sdn-ob:s:sdn_notice}
|
|
|
|
|
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\item SDN控制器为JAVA实现,有时候WEB存在缓存,
|
|
|
|
|
导致数据显示不及时,在流表更新显示(两次实验对比)时,
|
|
|
|
|
先清空历史缓存数据后再显示。
|
|
|
|
|
\item Python脚本为一个http协议的客户端脚本程序,
|
|
|
|
|
通过http协议及REST API的路径请求或设置SDN控制器WEB的对应功能模块,
|
|
|
|
|
获取或设置该模块的返回数据或输入参数,传输数据类型为json格式。
|
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
|
|
\subsection{考核方法}
|
|
|
|
|
\label{subsec:c:sdn-ob:s:sdn_criterion}
|
|
|
|
|
|
|
|
|
|
完成本次实验,需要提交一份实验报告和一分程序输出日志。
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\item (20分)在规定时间内完成实验,并提交实验成果;
|
|
|
|
|
\item (40分)根据实现OpenFlow消息类型的多少分计分,简单类型5分,复杂类型10分;
|
|
|
|
|
\item (20分)通过脚本设置可以实现两个测试主机ping能和不能ping通;
|
|
|
|
|
\item (20分)通过网上搜索学习,
|
|
|
|
|
使用其他多个REST~API查询到了交换机更多的数据内容;
|
|
|
|
|
\item (10分)实验报告与源代码内容完整、格式整洁。
|
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
|
|