SDN控制器之POX篇

时间:2021-11-11 10:55:10

1. 安装POX

POX基于Python2.7的环境运行,官方版本的POX可以运行在Windows、Mac OS、以及Linux操作系统中。POX源码已在github发布,可将POX的源码下载到本地机器进行安装使用。

在Linux系统下可以直接使用git 将pox源码下载下来,如:

$git clone http://github.com/noxrepo/pox
  • 1

或在 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/extgit clone https://github.com/MurphyMc/poxdesk
  • 1
  • 2

2)获取qooxdoo

下载qooxdoo代码压缩包,然后把解压后文件夹名字改成qx

cd poxdeskwget http://downloads.sourceforge.net/qooxdoo/qooxdoo-2.0.2-sdk.zipunzip qooxdoo-2.0.2-sdk.zipmv qooxdoo-2.0.2-sdk qx
  • 1
  • 2
  • 3
  • 4

3)初始化poxdesk 
进入poxdesk目录,执行命令./generate.py

cd poxdesk./generate.py
  • 1
  • 2
  • 3

4)启动POX

cd ../../.../pox.py samples.pretty_log web messenger messenger.log_service messenger.ajax_transport openflow.of_service poxdesk
  • 1
  • 2

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
  • 1
  • 2

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9


(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 
  • 1
  • 2
  • 3
  • 4

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 6633kill 3204(进程号)
  • 1
  • 2

开启mininet执行:

mn --controller=remote,ip=192.168.0.105 --topo=tree,2,2mininet> dpctl dump-flows                   mininet>pingallmininet> dpctl dump-flows             //触发flow entry下发flow entry
  • 1
  • 2
  • 3
  • 4


(2)流表测试


1,启动pox:

python pox.py openflow.of_01 --address=192.168.0.105 --port=6633 py
  • 1

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> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3,添加流表:

POX> from pox.lib.addresses import IPAddrPOX> from pox.lib.addresses import EthAddrPOX> import pox.openflow.libopenflow_01 as of           //导出核心模块,并命名为ofPOX> core.openflow.connections.keys()           //获取连接控制端的openflow switch的key[1]POX>msg=of.ofp_flow_mod()               //编辑消息POX>msg.priority=3POX>msg.match.in_port=1POX>msg.actions.append(of.ofp_action_output(port=2))POX>core.openflow.connections[1].send(msg)POX> msg.match.in_port=2POX> msg.actions.append(of.ofp_action_output(port=1))POX> core.openflow.connections[1].send(msg)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

4,mininet端:

mininet> dpctl dump-flows   //显示已添加流表mininet> pingall           //可以ping通
  • 1
  • 2
  • 3


4.POX控制器下发openflow流表指南

启用pox控制器并同openflow交换机连接后,就可以使用pox控制器下发流表项了,这里先介绍一下下发流表项中各个匹配项和动作的命令。

匹配字段

  1. 编辑消息,消息类型为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,添加流表项。
  2. 设置规则的优先级 
    命令:POX> msg.priority=x 
    X为优先级数值,范围为1-65535
  3. 匹配入端口 
    命令:POX> msg.match.in_port=y 
    指定规则匹配的入端口值,y为交换机上端口对应的index值。
  4. 匹配源mac 
    命令:POX> msg.match.dl_src=EthAddr(“”)
  5. 匹配目的mac 
    命令:POX> msg.match.dl_dst=EthAddr(“ ”)
  6. 匹配以太类型 
    命令:POX> msg.match.dl_type=x 
    指定规则匹配ip类型报文
  7. 匹配vlan id 
    命令:POX> msg.match.dl_vlan=x 
    说明:dl_vlan必须为openflow交换机上存在的vlan
  8. 匹配vlan优先级 
    命令:POX> msg.match.dl_vlan_pcp=x 
    说明:dl_vlan_pcp必须在0-7之内。
  9. 匹配源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”
  10. 匹配目的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”
  11. 匹配协议类型 
    命令:POX> msg.match.nw_proto=x 
    说明:必须指定匹配的以太网类型,再匹配ip协议类型,如: 
    POX> msg.match.dl_type=0x800 
    POX> msg.match.nw_proto=6
  12. 匹配tos 
    命令:POX> msg.match.nw_tos=x 
    说明:必须指定匹配的以太网类型,再匹配tos值,如: 
    POX> msg.match.dl_type=0x800 
    POX> msg.match.nw_tos=64
  13. 匹配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
  14. 匹配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
  15. 在idle时间内,如果没有报文触发此动作,该条规则将删除 
    命令:POX> msg.idle_timeout=X 
    说明:X为时间值,单位为秒。缺省时为0,表示不老化删除。
  16. 在到达hard时间时,无论如何,该条规则将删除 
    命令:POX> msg.hard_timeout=X 
    说明:X为时间值,单位为秒。缺省时为0,表示不老化删除。 
    修改动作 
    若规则无动作则默认为丢弃;规则中没有显示的设置出端口的需要在相应动作之后添加出端口。
  17. 指定出端口动作 
    命令: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:和物理端口无关
  18. 转发指定的端口和队列 
    命令:POX> msg.actions.append(of.ofp_action_enqueue(port=x,queue_id=y))
  19. 改变目的mac为指定mac 
    命令:POX> msg.actions.append(of.ofp_action_dl_addr.set_dst(“”)) 
    说明:mac地址形式为ff:ff:ff:ff:ff:ff
  20. 改变源mac为指定mac 
    命令:POX> msg.actions.append(of.ofp_action_dl_addr.set_src(“”))
  21. 设定tos值 
    命令:POX> msg.actions.append(of.ofp_action_nw_tos(nw_tos=x))
  22. 设定vlan值 
    命令:POX> msg.actions.append(of.ofp_action_vlan_vid(vlan_vid=x))
  23. 设定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=3POX>msg.match.in_port=193POX>msg.actions.append(of.ofp_action_output(port=194))POX>core.openflow.connections[13136560386L].send(msg)
  • 1
  • 2
  • 3
  • 4
  • 5

说明:[13136560386L]为在POX和openflow交换机连接上时,使用命令POX>core.openflow.connections.keys()获取的交换机的key,每次下发流表项或者删除,修改流表项,这个key都是相同的。

2. 下发匹配目的MAC地址,动作为出端口的流表项 
命令:

POX>msg=of.ofp_flow_mod()POX>msg.priority=3POX>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)
  • 1
  • 2
  • 3
  • 4
  • 5

3. 下发匹配以太网类型,动作为出端口和队列的流表项 
命令:

POX>msg=of.ofp_flow_mod()POX>msg.priority=5POX>msg.match.dl_type=0x800POX>msg.actions.append(of.ofp_action_enqueue(queue_id=5,port=194))POX>core.openflow.connections[13136560386L].send(msg)
  • 1
  • 2
  • 3
  • 4
  • 5

4. 下发匹配源mac地址,动作为设置vlan 并指定出端口的流表项 
命令:

POX>msg=of.ofp_flow_mod()POX>msg.priority=5POX>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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5. 下发匹配入端口,动作为设置vlan、cos,并指定出端口的流表项 
命令:

POX>msg=of.ofp_flow_mod()POX>msg.priority=5POX>msg.match.in_port=193POX>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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

6. 删除流表项 
命令:

POX>msg=of.ofp_flow_mod(command=3)POX>core.openflow.connections[13136560386L].send(msg)
  • 1
  • 2

说明:此命令是删除所有的流表项

7. 删除特定的流表项 
命令:

POX>msg=of.ofp_flow_mod(command=4)POX>msg.wildcards= 4194302POX>msg.priority=5POX>core.openflow.connections[13136560386L].send(msg)
  • 1
  • 2
  • 3
  • 4

说明:删除特定的流表项就是将command值为4,并且精确匹配需要删除的流表项的匹配字段和动作。

8. 修改流表项 
命令:

POX>msg=of.ofp_flow_mod(command=2)POX>msg.priority=5POX>msg.match.in_port=193POX>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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

说明:修改流表项,即修改这条流表的动作。


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中进行分析