1. 安装 POX
POX 基于 Python2.7 的环境运行, 官方版本的 POX 可以运行在 Windows,Mac OS, 以及 Linux 操作系统中. POX 源码已在 github 发布, 可将 POX 的源码下载到本地机器进行安装使用.
在 Linux 系统下可以直接使用 git 将 pox 源码下载下来, 如:
$git clone http://github.com/noxrepo/pox
或在 https://github.com/pkpk8/pox 下载
2. 配置 POX(可选)
(1)修改监听端口
POX 的监听端口默认是 6633, 修改监听端口的方式有以下两种:
1)临时修改方法
每次启动 POX 时指定监听端口, 如指定的端口为 6636, 则在命令行后添加:
openflow.of_01 -port=6636
2)修改控制器的默认端口方法
修改 / pox/openflow/of_01.py 文件, 如指定的端口为 6636, 则将文件中所有的 port=6633 改为 port=6636.
(2)配置 web 界面端口
1)获取 POXDesk
- cd pox/ext
- git clone https://github.com/MurphyMc/poxdesk
2)获取 qooxdoo
下载 qooxdoo 代码压缩包, 然后把解压后文件夹名字改成 qx
- cd poxdesk
- wget http://downloads.sourceforge.net/qooxdoo/qooxdoo-2.0.2-sdk.zip
- unzip qooxdoo-2.0.2-sdk.zip
- mv qooxdoo-2.0.2-sdk qx
3)初始化 poxdesk
进入 poxdesk 目录, 执行命令./generate.py
- cd poxdesk
- ./generate.py
4)启动 POX
cd ../../..
./pox.py samples.pretty_log web messenger messenger.log_service messenger.ajax_transport openflow.of_service poxdesk
Samples.pretty.log 是一个组件, 可以让 pox 开启的时候有字体有颜色, 不添加也可以, 但是界面比较难看.
这种启动 pox-ui 的方式只能启动监听并且开启 ui 视图, 但是无法给 switch 下发消息(poxdesk 的 web 中的 terminal 是打算用其他虚拟 of-switch 的工具来控制下发规则, 但是我们是真实的 of-switch)
完整的使用方式如下:
./pox.py samples.pretty_log web messenger messenger.log_service
messenger.ajax_transport openflow.of_service poxdesk openflow.discovery poxdesk.tinytopo py
poxdesk.tinytopo 可以自动识别 topo. 上面命令的结尾添加 py 就可以出现熟悉的 pox > 命令模式, 这时可以在 web 上看到下联的 of-switch.
5)访问 Web
用浏览器访问 localhost:8000/poxdesk, 默认端口 8000
点击网页左下角的图标 pox, 可以打开许多小框.
3.POX 加 mininet 测试
把环境都安装好了之后, 分别在 terminal 下输入命令启动 pox 和 poxdesk(启动命令以上的 github 的 guide 中都有), 然后启动 mininet(sudo mn), 最后在浏览器中打开 http://127.0.0.1:8000/poxdesk/source/ , 在浏览器左下角的 POX 按钮处选择 topo viewer, 然后在 mininet 动态配置拓扑, 即可以在 topo viewer 中看到可视化的拓扑.
mininet 安装步骤:
- # git clone git://github.com/mininet/mininet
- # cd mininet
- # cat INSTALL
- # ./util/install.sh -nfv // 只安装 openflow 交换机, ovs; 若参数为 - a, 将 pox 等一并安装
- # mn --version // 查看版本
- # 卸载命令
- sudo rm -rf /usr/local/bin/mn /usr/local/bin/mnexec /usr/local/lib/python*/*/*mininet*/usr/local/bin/ovs-*/usr/local/sbin/ovs-*
- sudo apt-get remove mininet
(1)简单测试:
启动 POX 时, 需要运行 pox.py 或 debug-pox.py. 前者是在一般的情况下运行 POX, 后者主要用于调试 POX 控制器, 因此如果要在 POX 中做开发, 通常会选用 debug-pox.py 来启动 POX.POS 启动命令中的可选参数主要包括 verbose,no-cli,no-openflow, 具体描述信息及其他参数可以借助命令./pox.py -help 查看.
启动 pox:
cd pox
./pox.py openflow.of_01 forwarding.l2_learning
或
./pox.py samples.pretty_log web messenger messenger.log_service messenger.ajax_transport openflow.of_service poxdesk poxdesk.terminal poxdesk.tinytopo openflow.discovery forwarding.l2_learning py
pox.py 是程序的入口, 需要 openflow.of_01 库解释后面的参数, forwarding.l2_learning 为 POX 提供的组件. POX 默认开启 6633 端口监听.
poxdesk.tinytopo 可以自动识别 topo,poxdesk.terminal 可以使用 linux terminal(在 web 上操作 terminal). 上面命令的结尾添加 py 就可以出现熟悉的 pox > 命令模式, 这时可以在 web 上看到下联的 of-switch.
若出现端口占用问题:
- netstat -anp|grep 6633
- kill 3204(进程号)
开启 mininet 执行:
- mn --controller=remote,ip=192.168.0.105 --topo=tree,2,2
- mininet> dpctl dump-flows
- mininet>pingall
- mininet> dpctl dump-flows // 触发 flow entry 下发 flow entry
(2)流表测试
1, 启动 pox:
python pox.py openflow.of_01 --address=192.168.0.105 --port=6633 py
2, 启动 mininet:
若使用 virtualbox 启动, ifconfig 得到其 ip 为 192.168.0.106
开启新终端登入 mininet, 密码 mininet:
- ssh -X mininet@192.168.0.106
- sudo mn --controller=remote,ip=192.168.0.105 // 设置控制器
- mininet> dpctl dump-flows
- mininet>pingall // 无匹配流表, 无法 ping 通
- mininet> dump
- <Host h1: h1-eth0:10.0.0.1 pid=1980>
- <Host h2: h2-eth0:10.0.0.2 pid=1984>
- <OVSSwitch s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=1989>
- <RemoteController{'ip': '192.168.0.105'} c0: 192.168.0.105:6633 pid=1974>
3, 添加流表:
- POX> from pox.lib.addresses import IPAddr
- POX> from pox.lib.addresses import EthAddr
- POX> import pox.openflow.libopenflow_01 as of // 导出核心模块, 并命名为 of
- POX> core.openflow.connections.keys() // 获取连接控制端的 openflow switch 的 key
- [1]
- POX>msg=of.ofp_flow_mod() // 编辑消息
- POX>msg.priority=3
- POX>msg.match.in_port=1
- POX>msg.actions.append(of.ofp_action_output(port=2))
- POX>core.openflow.connections[1].send(msg)
- POX> msg.match.in_port=2
- POX> msg.actions.append(of.ofp_action_output(port=1))
- POX> core.openflow.connections[1].send(msg)
4,mininet 端:
- mininet> dpctl dump-flows // 显示已添加流表
- mininet> pingall // 可以 ping 通
4.POX 控制器下发 openflow 流表指南
启用 pox 控制器并同 openflow 交换机连接后, 就可以使用 pox 控制器下发流表项了, 这里先介绍一下下发流表项中各个匹配项和动作的命令.
匹配字段
编辑消息, 消息类型为 flowmod
命令: POX> msg=of.ofp_flow_mod(command=0)
参数: command:0 为 ADD(添加流),1 为 MODIFY,2 为 MODIFY_STRICT(严格匹配掩码和优先级修改流规则),3 为 DELETE(删除所有流规则),4 为 DELETE_STRICT(严格匹配掩码和优先级删除流规则)
缺省情况下, 即不标明参数 command, 如: msg=of.ofp_flow_mod(),command=0, 添加流表项.
设置规则的优先级
命令: POX> msg.priority=x
X 为优先级数值, 范围为 1-65535
匹配入端口
命令: POX> msg.match.in_port=y
指定规则匹配的入端口值, y 为交换机上端口对应的 index 值.
匹配源 mac
命令: POX> msg.match.dl_src=EthAddr("")
匹配目的 mac
命令: POX> msg.match.dl_dst=EthAddr(" ")
匹配以太类型
命令: POX> msg.match.dl_type=x
指定规则匹配 ip 类型报文
匹配 vlan id
命令: POX> msg.match.dl_vlan=x
说明: dl_vlan 必须为 openflow 交换机上存在的 vlan
匹配 vlan 优先级
命令: POX> msg.match.dl_vlan_pcp=x
说明: dl_vlan_pcp 必须在 0-7 之内.
匹配源 ip 地址
命令: POX> msg.match.nw_src="A.B.C.D/X"
说明: 下发匹配源 ip 地址时, 必须指定匹配的以太类型, 如:
- POX> msg.match.dl_type=0x800
- POX> msg.match.nw_src="192.168.2.133/24"
匹配目的 ip 地址
命令: POX> msg.match.nw_dst="A.B.C.D/X"
说明: 下发匹配目的 ip 地址时, 必须指定匹配的以太类型, 如:
- POX> msg.match.dl_type=0x800
- POX> msg.match.nw_dst="192.168.2.133/24"
匹配协议类型
命令: POX> msg.match.nw_proto=x
说明: 必须指定匹配的以太网类型, 再匹配 ip 协议类型, 如:
- POX> msg.match.dl_type=0x800
- POX> msg.match.nw_proto=6
匹配 tos
命令: POX> msg.match.nw_tos=x
说明: 必须指定匹配的以太网类型, 再匹配 tos 值, 如:
- POX> msg.match.dl_type=0x800
- POX> msg.match.nw_tos=64
匹配 tcp 源端口
命令: POX> msg.match.tp_src=X
说明: 必须指定匹配的以太网类型, 再匹配 ip 协议类型, 最后匹配 tcp port, 如:
- POX> msg.match.dl_type=0x800
- POX> msg.match.nw_proto=6
- POX> msg.match.tp_src=179
匹配 tcp 目的端口
命令: POX> msg.match.tp_dst=X
说明: 必须指定匹配的以太网类型, 再匹配 ip 协议类型, 最后匹配 tcp port, 如:
- POX> msg.match.dl_type=0x800
- POX> msg.match.nw_proto=6
- POX> msg.match.tp_dst=179
在 idle 时间内, 如果没有报文触发此动作, 该条规则将删除
命令: POX> msg.idle_timeout=X
说明: X 为时间值, 单位为秒. 缺省时为 0, 表示不老化删除.
在到达 hard 时间时, 无论如何, 该条规则将删除
命令: POX> msg.hard_timeout=X
说明: X 为时间值, 单位为秒. 缺省时为 0, 表示不老化删除.
修改动作
若规则无动作则默认为丢弃; 规则中没有显示的设置出端口的需要在相应动作之后添加出端口.
指定出端口动作
命令: POX> msg.actions.append(of.ofp_action_output(port=X))
说明: port 号是 openflow vlan 内的端口.
其中, port 值可以为特殊参数值, IN_PORT = 0xfff8: 从入端口将报文发出. FLOOD= 0xfffb: 除了入端口和 stp 不允许的端口的所有端口. ALL = 0xfffc: 除了入端口的其余端口. CONTROLLER = 0xfffd: 发送给控制器. NONE = 0xffff: 和物理端口无关
转发指定的端口和队列
命令: POX> msg.actions.append(of.ofp_action_enqueue(port=x,queue_id=y))
改变目的 mac 为指定 mac
命令: POX> msg.actions.append(of.ofp_action_dl_addr.set_dst(""))
说明: mac 地址形式为 ff:ff:ff:ff:ff:ff
改变源 mac 为指定 mac
命令: POX> msg.actions.append(of.ofp_action_dl_addr.set_src(""))
设定 tos 值
命令: POX> msg.actions.append(of.ofp_action_nw_tos(nw_tos=x))
设定 vlan 值
命令: POX> msg.actions.append(of.ofp_action_vlan_vid(vlan_vid=x))
设定 vlan cos 值
命令: POX> msg.actions.append(of.ofp_action_vlan_pcp(vlan_pcp=x))
说明: 设置 cos 值时必须先设置 vlan id, 如:
- POX> msg.actions.append(of.ofp_action_vlan_vid(vlan_vid=3))
- POX> msg.actions.append(of.ofp_action_vlan_pcp(vlan_pcp=4))
POX 使用实例
1. 下发匹配入端口, 动作为出端口的流表项
命令:
- POX>msg=of.ofp_flow_mod()
- POX>msg.priority=3
- POX>msg.match.in_port=193
- POX>msg.actions.append(of.ofp_action_output(port=194))
- POX>core.openflow.connections[13136560386L].send(msg)
说明:[13136560386L]为在 POX 和 openflow 交换机连接上时, 使用命令 POX>core.openflow.connections.keys()获取的交换机的 key, 每次下发流表项或者删除, 修改流表项, 这个 key 都是相同的.
2. 下发匹配目的 MAC 地址, 动作为出端口的流表项
命令:
- POX>msg=of.ofp_flow_mod()
- POX>msg.priority=3
- POX>msg.match.dl_src=EthAddr("ff:ff:ff:ff:ff:ff")
- POX>msg.actions.append(of.ofp_action_output(port=194))
- POX>core.openflow.connections[13136560386L].send(msg)
3. 下发匹配以太网类型, 动作为出端口和队列的流表项
命令:
- POX>msg=of.ofp_flow_mod()
- POX>msg.priority=5
- POX>msg.match.dl_type=0x800
- POX>msg.actions.append(of.ofp_action_enqueue(queue_id=5,port=194))
- POX>core.openflow.connections[13136560386L].send(msg)
4. 下发匹配源 mac 地址, 动作为设置 vlan 并指定出端口的流表项
命令:
- POX>msg=of.ofp_flow_mod()
- POX>msg.priority=5
- POX>msg.match.dl_src=EthAddr("00:03:0f:01:12:43")
- POX>msg.actions.append(of.ofp_action_vlan_vid(vlan_vid=3))
- POX>msg.actions.append(of.ofp_action_output(port=194))
- POX>core.openflow.connections[13136560386L].send(msg)
5. 下发匹配入端口, 动作为设置 vlan,cos, 并指定出端口的流表项
命令:
- POX>msg=of.ofp_flow_mod()
- POX>msg.priority=5
- POX>msg.match.in_port=193
- POX>msg.actions.append(of.ofp_action_vlan_vid(vlan_vid=4))
- POX>msg.actions.append(of.ofp_action_vlan_pcp(vlan_pcp=5))
- POX>msg.actions.append(of.ofp_action_output(port=194))
- POX>core.openflow.connections[13136560386L].send(msg)
6. 删除流表项
命令:
- POX>msg=of.ofp_flow_mod(command=3)
- POX>core.openflow.connections[13136560386L].send(msg)
说明: 此命令是删除所有的流表项
7. 删除特定的流表项
命令:
- POX>msg=of.ofp_flow_mod(command=4)
- POX>msg.wildcards= 4194302
- POX>msg.priority=5
- POX>core.openflow.connections[13136560386L].send(msg)
说明: 删除特定的流表项就是将 command 值为 4, 并且精确匹配需要删除的流表项的匹配字段和动作.
8. 修改流表项
命令:
- POX>msg=of.ofp_flow_mod(command=2)
- POX>msg.priority=5
- POX>msg.match.in_port=193
- POX>msg.actions.append(of.ofp_action_vlan_vid(vlan_vid=4))
- POX>msg.actions.append(of.ofp_action_vlan_pcp(vlan_pcp=5))
- POX>msg.actions.append(of.ofp_action_output(port=194))
- POX>core.openflow.connections[13136560386L].send(msg)
说明: 修改流表项, 即修改这条流表的动作.
5.POX 组件介绍
按照组件的功能进行分类:
L2 层地址学习, 洪泛
- forwarding.hub
- forwarding.l2_learning
- forwarding.l2_pairs
- forwarding.l2_multi
- forwarding.l2_nx
L3 层地址学习
forwarding.l3_learning
构建拓扑
- openflow.discovery
- openflow.spanning_tree
- forwarding.topo_proactive
openflow 连接相关
- openflow.of_01
- misc.full_payload
- openflow.keepalive
pox 内部服务
- py
- web.webcore
- messenger
- openflow.debug
pox 网络服务应用
- proto.arp_responder
- proto.pong
- proto.dns_spy
- proto.dhcp_client
- proto.dhcpd
- misc.nat
- misc.ip_loadbalancer
pox 功能扩展
- info.packet_dump
- misc.of_tutorial
- misc.mac_blocker
- misc.gephi_topo
- openflow.webservice
组件说明:
py
POX 的交互式 Python 解释执行组件, 用于 DEBUG 和交互式实验. 默认执行, 除非添加命令 -no-cli. 其他组件可以向该解释器添加函数和值.
forwarding.hub
该组件每个交换机添加洪泛通配符规则, 将所有交换机等效于 ethernet 集线器
forwarding.l2_learning
该组件使 opennflow 交换机实现 L2 链路层上的地址学习(类似网桥). 但当该组件学习地址学习时, 向流表下发的规则会尽可能的准确, 而不仅仅是 L2 层的地址. 例如不同的 TCP 连接将产生不同的表项.
forwarding.l2_pairs
类似于 forwarding.l2_learning,l2_pairs 让交换机进行地址学习, 但该组件是尽可能的简化规则学习, 所有安装的表项时只使用 L2 层信息(如 Mac 地址).
forwarding.l3_learning
该组件并不是一个完整的 Router, 该组件是可 POX 的 packet library(代码)的一个实现样例, 可以构造 ARP 请求和回复. l3_learning 关心 IP 从哪来, 但并不关心 IP 的填充域, 如子网等.
forwarding.l2_multi
L2 层地址学习, 但该层的学习不是单个交换机的独立学习, 而是通过 openflow.discovery 交换机之间交换拓扑信息, 学习整个网络的拓扑结构. 只要网络中有一个交换机学习到一个新的 Mac 地址及其位置, 所有的交换机就都能学会.
forwarding.l2_nx
Open vSwitch 的 quick-and-dirty 组件, 需要使用 Openvswitch 的 Nicira 扩展安装.
forwarding.topo_proactive
基于重要拓扑的 IP 地址安装规则. 通过 DHCP 进行地址分配. 所有的主机都必须用指定的 IP 地址, 绝大部分规则都是主动安装(?). 该组件被添加至聚合规则复用分支中, 路由编码基于 l2_multi 组件. 该组件依赖 openflow.discovery 以及 openflow.spanning_tree 组件(有待确认).
openflow.spanning_tree
该组件使用 discovery 组件来创建网络拓扑的视图, 构造一棵生成树, 然后使不在生成树中的交换机端口的洪泛功能失效, 使得网络中不存在洪泛回路. 需要注意的是该组件同生成树协议没有很大关系, 只是有相似的目的. 两个选项:
-no-flood, 只要交换机连接上了就使该交换机的所有端口洪泛失效, 对于某些端口, 稍后将使能.
-hold-down, 防止洪泛控制在一个完整的发现回路完成前被改变
因此该组件最安全的的使用方法是
openflow.spanning_tree -no-flood -hold-down .
openflow.webservice
Openflow 的一个简单 JSON-RPC-ish web service 交互式接口, 由 of_service 信息服务派生而来, 依赖于 webcore 组件. 可以使用 HTTP POST 方式发送 JSON 进行访问.
目前支持的方法有:
method
get_flow_stats, 获取流表的表项
get_switch_desc, 获取指定交换机详细信息
get_switches, 获取交换机列表和基本信息
set_table , 设置指定交换机的流表
web.webcore
在 Pox 进程中启动一个 web 服务, 其他组件可以通过它提供静态或动态内容.
messenger
该组件通过双向 JSON 消息为 POX 在进程间提供了一个交互接口. 该组件本质上是 API, 通过 TCP Socket 和 HTTP 进行通信. 具体的功能通过 Services 实现. messenger.log_service 允许远程操作 log(读 log 信息, 配置 log 等).openflow.of_service 允许一下 Openflow 的操作(如显示交换机列表, 设置流表表项等)../tools/pox-log.py 是一个独立的 Python 应用, 可以通过 TCP 同 log 服务进行交互.
openflow.of_01
该组件同 openflow 1.0 协议版本的交换机 进行通讯, 默认启动.
openflow.discovery
该组件在交换机之间使用特制的 LLDP 报文来发现整个网络的拓扑结构. 当链路生效或者失效时, 该组件都会产生一个事件(Raise Events).
openflow.debug
加载该组件将导致 POX 创建 pcap 追踪(进行抓包), 包括 openflow 报文, 可导入 wireshark 进行分析. 该工具并不能完全代替 wireshark 或 tcpdump, 不过有一个比较好的特性是每一个 openflow 报文都一个完整的帧中.
openflow.keepalive
该组件令 POX 向已经连接的交换机周期性的发送 echo 请求. 但这会解决两个问题:
第一, 有些交换机 (包括推荐交换机) 会认为空闲连接意味着同控制器连接丢失, 将会在一段 silence 时间后断开连接.
第二, 如果网络与交换机断开, 控制器将不会立即获得一个 FIN 或 RST, 所以将会很难确定一个交换机失效. 通过周期行发送 echo 请求, 并分析交换机的响应, 即可解决该问题.
proto.pong
该组件是一个简单的检测 ICMP echo 请求和应答的样例组件
proto.arp_responder
该组件为一个 ARP 应用, 可以学习和代理 ARP 请求, 也可以通过查询静态的表项来回复 ARP 请求. 该组件提供了一个控制台交互界面来查询和修改 arp 表.
info.packet_dump
该组件将 packet_in 信息保存至 log 中, 有点类似于在交换机中运行 tcpdump
proto.dns_spy
检测 DNS 应答并存储应答结果, 其他组件可以通过 DNSSpy 检测这些信息.
proto.dhcp_client
DHCP 客户端, 在同其他组件进行联合时有用
proto.dhcpd
简单的 DHCP 服务器端, 服务器本身的默认地址为 192.168.0.254, 下发的地址域为 192.168.0.1~192.168.0.253, 同时宣称自身为网关和 DNS 服务器.
misc.of_tutorial
配合 openflow tutorial 使用的组件, 类似于简单的 hub, 但可以修改成 L2 learning 的交换机
misc.full_payload
默认情况下, 当一个数据包在交换机流表中没有命中时, 交换机只向控制器发送数据包的前 128bytes, 使用该组件可以将每一个交换机配置成发送整个数据包
misc.mac_blocker
具有 Tkinter-based 界面, 可以阻塞 Mac 地址
misc.nat
实现网络地址转换的组件(木有详细介绍)
misc.ip_loadbalancer
由 carp branch(不理解是啥)启用的 TCP 负载均衡器
misc.gephi_topo
检测拓扑结构, 并将其导入到 gephi 中进行分析
来源: https://blog.csdn.net/qq_15437629/article/details/45919417