POX的话,直接在根目录下进入到POX目录下,执行
mininet@mininet-vm:~/pox$ python pox.py log.level --DEBUG misc.of_tutorial
以上命令是开启DEBUG模式(输出更多信息). 创建一个of_tutorial类型的模型(类似于集线器工作)
创建完成后创建mininet实例,发现输出了一些信息
DEBUG:core:POX 0.2.0 (carp) going up...
DEBUG:core:Running on CPython (2.7.6/Oct 26 2016 20:30:19)
DEBUG:core:Platform is Linux-4.2.0-27-generic-x86_64-with-Ubuntu-14.04-trusty
INFO:core:POX 0.2.0 (carp) is up.
DEBUG:openflow.of_01:Listening on 0.0.0.0:6633
INFO:openflow.of_01:[None 1] closed
INFO:openflow.of_01:[00-00-00-00-00-01 2] connected
DEBUG:misc.of_tutorial:Controlling [00-00-00-00-00-01 2]
我们可以在h1 h2 h3中打开各自的终端xterm h1 h2 h3
, 然后使用tcpdump监听,(功能类似于wireshark,可以捕捉到进来的各种数据包), 方法是,在h2的终端中输入tcpdump -XX -i h2-eth0
,就开始监听了
在mininet下使用iperf试一下性能:
如果想使用交换机模式,则要进入到/pox/pox/misc中修改of_tutorial.py,删除act_like_switch中的特定注释,退出保存.
POX的API
当switch和controller连接的时候,就得到了一个connection.
connection.send(...)
就可以向switch发送OF消息
ofp_action_output类
用于switch的端口发送的消息
示例: 创建一个action, 发送数据包泛洪到所有端口
out_action = of.ofp_action_output(port = of.OFPP_FLOOD)
ofp_match类
如其名,用于匹配
比如有一些可以匹配的东西
dl_src - 数据链路层中的源MAC
dl_dst - 数据链路层中的目的MAC
in_port - 进入的端口
示例: 创建一个匹配,匹配来自端口3的数据包
match=of.ofp_match()
match.in_port = 3
ofp_packet_out OF报文
constructed packet -> switch构造的包,赋予ID为buffer_id
类型 | 含义 |
---|---|
buffer_id | the buffer_id of a buffer you wish to send. Dont set if sending a constructed packet. |
data | switch发送的原始数据(如果发送buffered packet则不要填写) |
action | 做出的动作 |
in_port | 从哪里抵达的端口 |
示例:
action = of.ofp_action_output(port = out_port)
msg.actions.append(action)
#send message to switch
self.connection.send(msg)
ofp_flow_mod OF报文
这个报文主要用来匹配传入数据包的某些字段
关键字:idle_timeout, hard_timeout, action, priority, buffer_id, in_port, match
示例:
fm = of.ofp_flow_mod()
fm.match.in_port = 3
fm.actions.append(of.ofp_action_output(port = 4))
*如果想看openflow常量,在~/openflow/include/openflow/openflow.h中,如果想看POX的openflow库文件,在pox/openflow/libopenflow_01.py中
POX的包解析器
用来将数据包分析成各个字段然后交给python处理. 分析库在pox/lib/packet/
中,每一个协议都有对应的解析文件
POX的工作过程
首先在init方法中,生成了一些重要常量
# Keep track of the connection to the switch so that we can
# send it messages!
self.connection = connection
# This binds our PacketIn event listener
connection.addListeners(self)
又生成了一个空变量去追踪MAC和端口的相互绑定
# Use this table to keep track of which ethernet address is on
# which switch port (keys are MACs, values are ports).
self.mac_to_port = {}
在act_like_hub方法中
调用了
self.resend_packet(packet_in, of.OFPP_ALL)
这里的OFPP_ALL就是全部端口,也可以使用OFPP_FLOOD
在resend_packet方法(转发)中,新建一个实例化报文,绑定了内容后,,给动作表绑定了目的端口,最终执行这个实例
写了三个小时,终于把of_tutorial.py中的switch部分初步完成了(不会python真的好惨啊). V0.1实现的功能是:
- 如果在流表中有转发信息,则直接转发
- 如果流表中没有,则广播信息
不知道为什么不能自动学习???这个BUG也太大了吧
# Copyright 2012 James McCauley
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This component is for use with the OpenFlow tutorial.
It acts as a simple hub, but can be modified to act like an L2
learning switch.
It's roughly similar to the one Brandon Heller did for NOX.
"""
from pox.core import core
import pox.openflow.libopenflow_01 as of
log = core.getLogger()
class Tutorial (object):
"""
A Tutorial object is created for each switch that connects.
A Connection object for that switch is passed to the __init__ function.
"""
def __init__ (self, connection):
# Keep track of the connection to the switch so that we can
# send it messages!
self.connection = connection
# This binds our PacketIn event listener
connection.addListeners(self)
# Use this table to keep track of which ethernet address is on
# which switch port (keys are MACs, values are ports).
self.mac_to_port = {}
def resend_packet (self, packet_in, out_port):
"""
Instructs the switch to resend a packet that it had sent to us.
"packet_in" is the ofp_packet_in object the switch had sent to the
controller due to a table-miss.
"""
msg = of.ofp_packet_out()
msg.data = packet_in
# Add an action to send to the specified port
action = of.ofp_action_output(port = out_port)
msg.actions.append(action)
# Send message to switch
self.connection.send(msg)
def act_like_hub (self, packet, packet_in):
"""
Implement hub-like behavior -- send all packets to all ports besides
the input port.
"""
# We want to output to all ports -- we do that using the special
# OFPP_ALL port as the output port. (We could have also used
# OFPP_FLOOD.)
self.resend_packet(packet_in, of.OFPP_ALL)
# Note that if we didn't get a valid buffer_id, a slightly better
# implementation would check that we got the full data before
# sending it (len(packet_in.data) should be == packet_in.total_len)).
def act_like_switch (self, packet, packet_in,port):
"""
Implement switch-like behavior.
"""
# Here's some psuedocode to start you off implementing a learning
# switch. You'll need to rewrite it as real Python code.
# Learn the port for the source MAC
self.mac_to_port[str(packet.src)] = port
if str(packet.dst) in self.mac_to_port:
# Send packet out the associated port
self.resend_packet(packet_in, self.mac_to_port[str(packet.dst)])
# Once you have the above working, try pushing a flow entry
# instead of resending the packet (comment out the above and
# uncomment and complete the below.)
log.debug("I, the controller, send a packet! What are you doing, Switch?")
# Maybe the log statement should have source/destination/port?
#msg = of.ofp_flow_mod()
#
## Set fields to match received packet
#msg.match = of.ofp_match.from_packet(packet)
#
#< Set other fields of flow_mod (timeouts? buffer_id?) >
#
#< Add an output action, and send -- similar to resend_packet() >
else:
# Flood the packet out everything but the input port
# This part looks familiar, right?
self.resend_packet(packet_in, of.OFPP_ALL)
def _handle_PacketIn (self, event):
"""
Handles packet in messages from the switch.
"""
packet = event.parsed # This is the parsed packet data.
if not packet.parsed:
log.warning("Ignoring incomplete packet")
return
packet_in = event.ofp # The actual ofp_packet_in message.
# Comment out the following line and uncomment the one after
# when starting the exercise.
#self.act_like_hub(packet, packet_in)
self.act_like_switch(packet, packet_in,event.port)
def launch ():
"""
Starts the component
"""
def start_switch (event):
log.debug("Controlling %s" % (event.connection,))
Tutorial(event.connection)
core.openflow.addListenerByName("ConnectionUp", start_switch)