目录
- 安装RYU和Mininet
- 下载安装Pycharm
- 写一个RYU应用程序
- RYU的组成
- Ryu应用程序接口
- Ryu 应用程序编程模型
- 线程、事件和事件队列
- 上下文(Contexts)
- 创建 Ryu 应用程序
- 观察事件(Observe events)
- 生成事件(Generate events)
- 事件类
- OpenFlow 事件类
- ryu.base.app_manager.RyuApp
- ryu.controller.handler.set_ev_cls
- ryu.controller.controller.Datapath
- ryu.controller.event.EventBase
- ryu.controller.event.EventRequestBase
- ryu.controller.event.EventReplyBase
- ryu.controller.ofp_event.EventOFPStateChange
- ryu.controller.ofp_event.EventOFPPortStateChange
- ryu.controller.dpset.EventDP
- ryu.controller.dpset.EventPortAdd
- ryu.controller.dpset.EventPortDelete
- ryu.controller.dpset.EventPortModify
- ryu.controller.network.EventNetworkPort
- ryu.controller.network.EventNetworkDel
- ryu.controller.network.EventMacAddress
- ryu.controller.tunnels.EventTunnelKeyAdd
- ryu.controller.tunnels.EventTunnelKeyDel
- ryu.controller.tunnels.EventTunnelPort
- 库
安装RYU和Mininet
mininet与ryu的安装
【RYU】python2.7环境安装RYU的方法及遇到的坑
下载安装Pycharm
写一个RYU应用程序
实现目标: OpenFlow switch充当dumb layer 2 switch
定义一个新的 RyuApp 子类
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
from ryu.ofproto import ofproto_v1_0
class L2Switch(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(L2Switch, self).__init__(*args, **kwargs)
# 当 Ryu 收到 OpenFlow packet_in消息时,将调用此函数。
# “set_ev_cls”装饰器告诉 Ryu 何时应调用修饰函数。
# ofp_event.EventOFPPacketIn表示此函数调用哪种类型的事件,这里是packet_in消息
# MAIN_DISPATCHER指示交换机的状态。注意,在 Ryu 和交换机之间的协商完成之前会忽略packet_in消息。使用“MAIN_DISPATCHER”作为第二个参数意味着只有在协商完成后才会调用此函数。
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
msg = ev.msg# ev.msg 是表示packet_in数据结构的对象
dp = msg.datapath# msg.datapath 是一个表示数据路径(交换机)的对象
ofp = dp.ofproto
ofp_parser = dp.ofproto_parser
# dp.ofproto 和 dp.ofproto_parser是表示 Ryu 和 switch 协商的 OpenFlow 协议的对象
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)]
# OFPActionOutput 类与packet_out消息一起使用,以指定要从中发送数据包的交换机端口。此应用程序使用 OFPP_FLOOD 标志来指示应在所有端口上发送数据包(泛洪)。
# OFPPacketOut 类用于生成packet_out消息。如果使用 OpenFlow 消息类对象调用 Datapath 类的 send_msg 方法,Ryu 将生成在线数据格式并将其发送到交换机。
data = None
if msg.buffer_id == ofp.OFP_NO_BUFFER:
data = msg.data
out = ofp_parser.OFPPacketOut(
datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port,
actions=actions, data = data)
dp.send_msg(out)
值得注意的是dumb layer 2 switch不具备学习功能,接下来看一下ryu的具体组成。
RYU的组成
可执行文件
bin/ryu-manager
主可执行文件。
基础组件
ryu.base.app_manager
Ryu 应用程序的集中管理。
- 加载 Ryu 应用程序
- 为 Ryu 应用程序提供contexts
- 在 Ryu 应用程序之间路由消息
OpenFlow controller
ryu.controller.controller
OpenFlow控制器的主要组件。
- 处理来自交换机的连接
- 生成事件并将其路由到适当的实体,如 Ryu 应用程序
ryu.controller.dpset
管理交换机。
计划由 ryu/topology取代。
ryu.controller.ofp_event
OpenFlow 事件定义。
ryu.controller.ofp_handler
基本的 OpenFlow 处理,包括协商。
OpenFlow 有线协议编码器和解码器
ryu.ofproto.ofproto_v1_0
OpenFlow 1.0 定义。
ryu.ofproto.ofproto_v1_0_parser
OpenFlow 1.0 的解码器/编码器实现。
ryu.ofproto.ofproto_v1_2
OpenFlow 1.2 定义。
ryu.ofproto.ofproto_v1_2_parser
OpenFlow 1.2 的解码器/编码器实现。
ryu.ofproto.ofproto_v1_3
OpenFlow 1.3 定义。
ryu.ofproto.ofproto_v1_3_parser
此模块实现了 OpenFlow 1.3.x。
此模块还实现了“OpenFlow Extensions for 1.3.X Pack 1”中显示的一些扩展。
ryu.ofproto.ofproto_v1_4
OpenFlow 1.4 definitions.
ryu.ofproto.ofproto_v1_4_parser
Decoder/Encoder implementations of OpenFlow 1.4.
ryu.ofproto.ofproto_v1_5
OpenFlow 1.5 definitions.
ryu.ofproto.ofproto_v1_5_parser
Decoder/Encoder implementations of OpenFlow 1.5.
Ryu applications
ryu.app.cbench
一个dumb OpenFlow 1.0 responder,用于对控制器框架进行基准测试。旨在与 oflops cbench 一起使用。
ryu.app.simple_switch
OpenFlow 1.0 L2 学习交换机实现。
ryu.topology
交换机和链路发现模块。
计划更换 ryu/controller/dpset。
库
ryu.lib.packet
Ryu 数据包库。TCP/IP 等常用协议的解码器/编码器实现。
ryu.lib.ovs
ovsdb 交互库。
ryu.lib.of_config
OF-Config 实现。
ryu.lib.netconf
ryu/lib/of_config使用的 NETCONF 定义。
ryu.lib.xflow
sFlow 和 NetFlow 的实现。
第三方库
ryu.contrib.ovs
打开 vSwitch python binding.由 ryu.lib.ovs 使用。
ryu.contrib.oslo.config
Oslo配置库。用于 ryu-manager 的命令行选项和配置文件。
ryu.contrib.ncclient
Python library for NETCONF client.由ryu.lib.of_config使用。
Ryu应用程序接口
Ryu 应用程序编程模型
线程、事件和事件队列
Ryu 应用程序是单线程实体,在 Ryu 中实现各种功能。事件是它们之间的消息。
Ryu 应用程序相互发送异步事件。除此之外,还有一些 Ryu 内部事件源不是 Ryu 应用程序。此类事件源的一个例子是OpenFlow控制器。虽然事件目前可以包含任意python对象,但不鼓励在Ryu应用程序之间传递复杂对象(例如unpickleable objects)。
每个 Ryu 应用程序都有一个事件的接收队列。队列是先进先出并保留事件的顺序。每个 Ryu 应用程序都有一个用于事件处理的线程。线程通过取消事件排队并为事件类型调用合适的事件处理程序来不断排出接收队列。由于事件处理程序是在事件处理线程的上下文中调用的,因此在阻塞时应小心。当事件处理程序被阻止时,将不会处理 Ryu 应用程序的进一步事件。
有一些事件用于在 Ryu 应用程序之间实现同步应用程序间调用。虽然此类请求使用与普通事件相同的机制,但它们的回复被放在专用于事务的队列中以避免死锁。
虽然线程和队列当前是使用 eventlet/greenlet 实现的,但强烈建议不要在 Ryu 应用程序中直接使用它们。
上下文(Contexts)
Contexts是在Ryu应用程序之间共享的普通python对象。对于新代码,不鼓励使用Contexts。
创建 Ryu 应用程序
Ryu应用程序是一个python模块,它定义了ryu.base.app_manager.RyuAppr的子类。如果在模块中定义了两个或多个此类类,则第一个类(按名称顺序)将由app_manager选取。Ryu 应用程序是单例的:仅支持给定 Ryu 应用程序的单个实例。
观察事件(Observe events)
Ryu 应用程序可以使用ryu.controller.handler.set_ev_cls装饰器注册自身以侦听特定事件。
生成事件(Generate events)
Ryu 应用程序可以通过调用适当的 ryu.base.app_manager.RyuApp 方法来引发事件,如send_event或send_event_to_observers。
事件类
事件类描述系统中生成的 Ryu 事件。按照约定,事件类名称以“Event”为前缀。事件由 Ryu 的核心部分或 Ryu 应用程序生成。Ryu 应用程序可以通过提供使用ryu.controller.handler.set_ev_cls修饰器的处理程序方法来注册其对特定类型事件的兴趣。
OpenFlow 事件类
ryu.controller.ofp_event模块导出描述从连接的交换机接收 OpenFlow 消息的事件类。按照惯例,它们被命名为ryu.controller.ofp_event.EventOFPxxxx,其中 xxxx 是相应 OpenFlow 消息的名称。例如,EventOFPPacketIn 表示 packet-in 消息。Ryu的OpenFlow控制器部分自动解码从交换机接收的OpenFlow消息,并将这些事件发送到使用ryu.controller.handler.set_ev_cls表示兴趣的Ryu应用程序。OpenFlow 事件类是以下类的子类。
class ryu.controller.ofp_event.EventOFPMsgBase(msg)
OpenFlow 事件类的基类。
OpenFlow 事件类至少具有以下属性:
- msg 描述相应 OpenFlow 消息的对象。(msg 对象还有一些其他成员,这些成员的值是从原始 OpenFlow 消息中提取的。)
- msg.datapath 一个 ryu.controller.controller.Datapath 实例,它描述了一个 OpenFlow 开关,我们从该交换机收到此 OpenFlow 消息。
- timestamp 数据路径实例生成此事件的时间戳。
ryu.base.app_manager.RyuApp
class ryu.base.app_manager.RyuApp(*_args, **_kwargs)
Ryu 应用程序的基类。
RyuApp 子类在 ryu 管理器加载所有请求的 Ryu 应用程序模块后实例化。__init__应该使用相同的参数调用RyuApp.init。以__init__发送任何事件都是非法的。
实例属性“name”是用于在 Ryu 应用程序之间路由消息的类的名称。(参看send_event)它被RyuApp.__init__设置为 class.name。不鼓励子类覆盖它。
OFP_VERSIONS= None
此 RyuApp 支持的 OpenFlow 版本列表。默认值为框架支持的所有版本。
例:
OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION,
ofproto_v1_2.OFP_VERSION]
如果在系统中加载了多个 Ryu 应用程序,则使用其OFP_VERSIONS的交集。
_CONTEXTS= {}
用于指定此 Ryu 应用程序要使用的上下文的字典。它的键是上下文的名称,其值是实现上下文的普通类。该类由app_manager实例化,实例在具有相同键 _CONTEXTS 成员的 RyuApp 子类之间共享。RyuApp 子类可以通过其__init__的 kwargs 获取对实例的引用,如下所示。
例:
_CONTEXTS = {
'network': network.Network
}
def __init__(self, *args, *kwargs):
self.network = kwargs['network']
_EVENTS= []
此 RyuApp 子类将生成的事件类的列表。当且仅当在与 RyuApp 子类不同的 python 模块中定义了事件类时,才应指定此项。
close()
拆解方法。方法名称 close 是为 python 上下文管理器选择的
classmethod context_iteritems()
返回应用程序上下文(key, contxt class)上的迭代器
reply_to_request(req,rep)
为send_request发送的同步请求发送答复。第一个参数应该是 EventRequestBase 的一个实例。第二个参数应该是 EventReplyBase 的一个实例。
send_event(name,ev,state=None)
将指定的事件发送到按名称指定的 RyuApp 实例。
send_event_to_observers(ev,state=None)
将指定的事件发送给此 RyuApp 的所有观察者。
send_request(rep)
发出同步请求。将 req.sync 设置为 True,将其发送到 req.dst 指定的 Ryu 应用程序,并阻止直到收到回复。返回收到的答复。该参数应该是 EventRequestBase 的一个实例。
start()
启动初始化完成后调用的 Hook。
class ryu.controller.dpset.DPSet(*args, **kwargs)
DPSet 应用程序管理连接到此控制器的一组交换机(数据路径)。
使用示例:
# ...(snip)...
from ryu.controller import dpset
class MyApp(app_manager.RyuApp):
_CONTEXTS = {
'dpset': dpset.DPSet,
}
def __init__(self, *args, **kwargs):
super(MyApp, self).__init__(*args, **kwargs)
# Stores DPSet instance to call its API in this app
self.dpset = kwargs['dpset']
def _my_handler(self):
# Get the datapath object which has the given dpid
dpid = 1
dp = self.dpset.get(dpid)
if dp is None:
self.logger.info('No such datapath: dpid=%d', dpid)
get(dp_id)
此方法返回给定数据路径 ID 的 ryu.controller.controller.Datapath 实例。
get_all()
此方法返回一个元组列表,该元组表示连接到此控制器的交换机的实例。该元组由数据路径 ID 和 ryu.controller.controller.Datapath 的实例组成。
返回值如下所示:
[ (dpid_A, Datapath_A), (dpid_B, Datapath_B), ... ]
get_port(dpid, port_no)
此方法返回给定数据路径 ID 和端口号的 ryu.controller.dpset.PortState 实例。 如果没有连接到此控制器的此类数据路径或不存在此类端口,则引发 ryu_exc.PortNotFound。
get_ports(dpid)
此方法返回给定数据路径 ID 的 ryu.controller.dpset.PortState 实例列表。 如果没有这样的数据路径连接到此控制器,则引发 KeyError。
ryu.controller.handler.set_ev_cls
ryu.controller.handler.set_ev_cls(ev_cls, dispatchers=None)
Ryu 应用程序的装饰器,用于声明事件处理程序。
装饰方法将成为事件处理程序。 ev_cls 是一个事件类,这个 RyuApp 想要接收它的实例。 dispatchers 参数指定应为此处理程序生成事件的以下协商阶段之一(或它们的列表)。 请注意,如果事件改变了阶段,则使用改变之前的阶段来检查兴趣。
- ryu.controller.handler.HANDSHAKE_DISPATCHER 发送和等待问候消息
- ryu.controller.handler.CONFIG_DISPATCHER 版本协商和发送的功能请求消息
- ryu.controller.handler.MAIN_DISPATCHER 已接收和发送的交换机功能消息集配置消息
- ryu.controller.handler.DEAD_DISPATCHER 断开与对等方的连接。或者由于一些不可恢复的错误而断开连接。
ryu.controller.controller.Datapath
class ryu.controller.controller.Datapath(socket, address)
描述连接到此控制器的 OpenFlow 交换机的类。
实例具有以下属性。
- id 64 位 OpenFlow 数据路径 ID。仅适用于ryu.controller.handler.MAIN_DISPATCHER阶段。
- ofproto 一个导出OpenFlow定义的模块,主要是规范中出现的常量,用于协商的OpenFlow版本。例如,openFlow 1.0 的ryu.ofproto.ofproto_v1_0。
- ofproto_parser 一个模块,用于为协商的OpenFlow版本导出OpenFlow有线消息编码器和解码器。例如,openFlow 1.0 的ryu.ofproto.ofproto_v1_0_parser。
- ofproto_parser.OFPxxxx(datapath,…) 可调用以准备给定交换机的 OpenFlow 消息。它可以在以后随Datapath.send_msg一起发送。xxxx 是消息的名称。例如,OFPFlowMod 用于 flow-mod 消息。争论取决于信息。
- set_xid(self, msg) 生成一个 OpenFlow XID 并将其放入 msg.xid 中。
- send_msg(self, msg) 将 OpenFlow 消息排队以发送到相应的交换机。如果 msg.xid 为 None,则在排队之前自动对邮件调用set_xid。
- send_packet_out 已弃用
- send_flow_mod 已弃用
- send_flow_del 已弃用
- send_delete_all_flows 已弃用
- send_barrier 将 OpenFlow 屏障消息排队以发送到交换机。
- send_nxt_set_flow_format 已弃用
- is_reserved_port 已弃用
ryu.controller.event.EventBase
class ryu.controller.event.EventBase
所有事件类的基础。
Ryu 应用程序可以通过创建子类来定义自己的事件类型。
ryu.controller.event.EventRequestBase
class ryu.controller.event.EventRequestBase
RyuApp.send_request同步请求的基类。
ryu.controller.event.EventReplyBase
class ryu.controller.event.EventReplyBase(dst)
RyuApp.send_reply 的同步请求回复的基类。
ryu.controller.ofp_event.EventOFPStateChange
class ryu.controller.ofp_event.EventOFPStateChange(dp)
用于协商阶段更改通知的事件类。
更改协商阶段后,将此类的实例发送给观察者。 一个实例至少具有以下属性。
- datapath ryu.controller.controller.Datapath 交换机实例
ryu.controller.ofp_event.EventOFPPortStateChange
class ryu.controller.ofp_event.EventOFPPortStateChange(dp, reason, port_no)
通知 Dtatapath 实例的端口状态变化的事件类。
此事件的执行类似于 EventOFPPortStatus,但 Ryu 将在更新 Datapath 实例的 dict 后发送此事件。 一个实例至少具有以下属性。
- datapath ryu.controller.controller.Datapath 交换机实例
- reason OFPPR_* 之一
- port_no 状态改变的端口号
ryu.controller.dpset.EventDP
class ryu.controller.dpset.EventDP(dp, enter_leave)
通知交换机连接/断开的事件类。
对于 OpenFlow 交换机,可以通过观察 ryu.controller.ofp_event.EventOFPStateChange 获得相同的通知。 一个实例至少具有以下属性。
- dp 交换机的 ryu.controller.controller.Datapath 实例
- enter 当交换机连接到我们的控制器时为真。假表示断开连接。
- ports 端口实例的列表。
ryu.controller.dpset.EventPortAdd
class ryu.controller.dpset.EventPortAdd(dp, port)
交换机端口状态“ADD”通知的事件类。
当向交换机添加新端口时会生成此事件。 对于 OpenFlow 交换机,可以通过观察 ryu.controller.ofp_event.EventOFPPortStatus 获得相同的通知。 一个实例至少具有以下属性。
- dp 交换机的 ryu.controller.controller.Datapath 实例
- port 端口号
ryu.controller.dpset.EventPortDelete
class ryu.controller.dpset.EventPortDelete(dp, port)
交换机端口状态“DELETE”通知的事件类。
当从交换机中删除端口时会生成此事件。 对于 OpenFlow 交换机,可以通过观察 ryu.controller.ofp_event.EventOFPPortStatus 获得相同的通知。 一个实例至少具有以下属性。
- dp 交换机的 ryu.controller.controller.Datapath 实例
- port 端口号
ryu.controller.dpset.EventPortModify
class ryu.controller.dpset.EventPortModify(dp, new_port)
交换机端口状态“Modify”通知的事件类。
当端口的某些属性发生更改时,会生成此事件。 对于 OpenFlow 交换机,可以通过观察 ryu.controller.ofp_event.EventOFPPortStatus 获得相同的通知。 一个实例至少具有以下属性。
- dp 交换机的 ryu.controller.controller.Datapath 实例
- port 端口号
ryu.controller.network.EventNetworkPort
class ryu.controller.network.EventNetworkPort(network_id, dpid, port_no, add_del)
用于通知端口到达和离开的事件类。
当 REST API 将端口引入网络或从网络中删除端口时,将生成此事件。 一个实例至少具有以下属性。
- network_id 网络标识
- dpid 端口所属交换机的 OpenFlow 数据路径 ID。
- port_no 端口的 OpenFlow 端口号
- add_del 如果为 True,则表示添加端口。False 表示删除端口。
ryu.controller.network.EventNetworkDel
class ryu.controller.network.EventNetworkDel(network_id)
网络删除的事件类。
此事件在 REST API 删除网络时生成。 一个实例至少具有以下属性。
- network_id 网络标识
ryu.controller.network.EventMacAddress
class ryu.controller.network.EventMacAddress(dpid, port_no, network_id, mac_address, add_del)
端点 MAC 地址注册的事件类。
此事件在 REST API 更新端点 MAC 地址时生成。 一个实例至少具有以下属性。
- network_id 网络标识
- dpid 端口所属交换机的 OpenFlow 数据路径 ID。
- port_no 端口的 OpenFlow 端口号
- mac_address 端口的旧 MAC 地址(如果add_del)为 False。否则为新的 MAC 地址。
- add_del 如果此事件是端口删除的结果,则为 false。否则为真。
ryu.controller.tunnels.EventTunnelKeyAdd
class ryu.controller.tunnels.EventTunnelKeyAdd(network_id, tunnel_key)
用于隧道密钥注册的事件类。
此事件在 REST API 注册或更新隧道密钥时生成。 一个实例至少具有以下属性。
- network_id 网络标识
- tunnel_key 隧道密钥
ryu.controller.tunnels.EventTunnelKeyDel
class ryu.controller.tunnels.EventTunnelKeyDel(network_id, tunnel_key)
用于隧道密钥注册的事件类。
此事件在 REST API 删除隧道密钥时生成。 一个实例至少具有以下属性。
- network_id 网络标识
- tunnel_key 隧道密钥
ryu.controller.tunnels.EventTunnelPort
class ryu.controller.tunnels.EventTunnelPort(dpid, port_no, remote_dpid, add_del)
隧道端口注册的事件类。
此事件在 REST API 添加或删除隧道端口时生成。 一个实例至少具有以下属性。
- dpid OpenFlow Datapath ID
- port_no OpenFlow 端口号
- remote_dpid 隧道对等体的 OpenFlow 端口号
- add_del 对于添加隧道,则为 True。为 false 表示删除。
库
数据包库
介绍
Ryu 数据包库可帮助您解析和构建各种协议数据包。dpkt是用于相同目的的流行库,但它不是为处理交错协议而设计的;vlan,mpls,gre等。
网络地址
除非另有指定,否则 MAC/IPv4/IPv6 地址是使用此库的人类可读字符串指定的。例如,‘08:60:6e:7f:74:e7’、 ‘192.0.2.1’、 ‘fe80::a60:6eff:fe7f:74e7’。
解析数据包
首先,让我们看一下如何使用该库来解析 OFPPacketIn 消息处理程序中接收的数据包。
from ryu.lib.packet import packet
@handler.set_ev_cls(ofp_event.EventOFPPacketIn, handler.MAIN_DISPATCHER)
def packet_in_handler(self, ev):
pkt = packet.Packet(array.array('B', ev.msg.data))
for p in pkt.protocols:
print p
使用收到的原始数据创建数据包类实例。然后,数据包库解析数据并创建包含该数据的协议类实例。数据包类“protocols”具有协议类实例。
如果收到 TCP 数据包,则会打印类似以下内容的内容:
<ryu.lib.packet.ethernet.ethernet object at 0x107a5d790>
<ryu.lib.packet.vlan.vlan object at 0x107a5d7d0>
<ryu.lib.packet.ipv4.ipv4 object at 0x107a5d810>
<ryu.lib.packet.tcp.tcp object at 0x107a5d850>
如果未使用 vlan,则会看到如下内容:
<ryu.lib.packet.ethernet.ethernet object at 0x107a5d790>
<ryu.lib.packet.ipv4.ipv4 object at 0x107a5d810>
<ryu.lib.packet.tcp.tcp object at 0x107a5d850>
使用数据包类迭代器访问特定的协议类实例。尝试检查 VLAN ID 是否使用了 VLAN:
from ryu.lib.packet import packet
@handler.set_ev_cls(ofp_event.EventOFPPacketIn, handler.MAIN_DISPATCHER)
def packet_in_handler(self, ev):
pkt = packet.Packet(array.array('B', ev.msg.data))
for p in pkt:
print p.protocol_name, p
if p.protocol_name == 'vlan':
print 'vid = ', p.vid
看到类似下面的内容:
ethernet <ryu.lib.packet.ethernet.ethernet object at 0x107a5d790>
vlan <ryu.lib.packet.vlan.vlan object at 0x107a5d7d0>
vid = 10
ipv4 <ryu.lib.packet.ipv4.ipv4 object at 0x107a5d810>
tcp <ryu.lib.packet.tcp.tcp object at 0x107a5d850>
构建数据包
需要创建要发送的协议类实例,通过add_protocol方法将它们添加到数据包类实例,然后调用序列化方法。有要发送的原始数据。下面的示例正在生成一个 arp 数据包。
from ryu.ofproto import ether
from ryu.lib.packet import ethernet, arp, packet
e = ethernet.ethernet(dst='ff:ff:ff:ff:ff:ff',
src='08:60:6e:7f:74:e7',
ethertype=ether.ETH_TYPE_ARP)
a = arp.arp(hwtype=1, proto=0x0800, hlen=6, plen=4, opcode=2,
src_mac='08:60:6e:7f:74:e7', src_ip='192.0.2.1',
dst_mac='00:00:00:00:00:00', dst_ip='192.0.2.2')
p = packet.Packet()
p.add_protocol(e)
p.add_protocol(a)
p.serialize()
print repr(p.data) # the on-wire packet
数据包库 API 参考
数据包类
class ryu.lib.packet.packet.Packet(data=None, protocols=None, parse_cls=<class ‘ryu.lib.packet.ethernet.ethernet’>)
数据包解码器/编码器类。
实例用于对单个数据包进行解码或编码。
data 是一个字节数组,用于描述要解码的原始数据报。 解码时,Packet 对象是可迭代的。 迭代值是协议(以太网、ipv4、…)标头和有效负载。 协议头是 packet_base.PacketBase 子类的实例。 有效载荷是一个字节数组。 它们以在线顺序迭代。
编码数据包时应省略数据。
add_protocol(proto)
为此数据包注册协议原型。
此方法仅在对数据包进行编码时才合法。
对数据包进行编码时,请注册一个协议(以太网、ipv4、…)标头以添加到此数据包中。在调用 self.serialize 之前,应按在线顺序注册协议标头。
classmethodfrom_jsondict(dict_, decode_string=, **additional_args)
从 JSON 样式词典创建实例。
使用 dict 指定的参数实例化此类。
此方法采用以下参数。
- dict_ 描述参数的字典。例如,{“Param1”: 100, “Param2”: 200}
- decode_string (可选)指定如何解码字符串。默认值为 base64。此参数仅用于在类属性中没有显式类型批注_TYPE属性的属性。
- additional_args (可选)构造函数的附加 kwargs。
get_protocol(protocol)
返回与指定协议匹配的第一个找到的协议。
get_protocols(protocol)
返回与指定协议匹配的协议列表。
serialize()
对数据包进行编码,并将生成的字节数组存储在 self.data 中。
此方法仅在对数据包进行编码时才合法。
流分析器类
class ryu.lib.packet.stream_parser.StreamParser
流式分析器基类。
此类的子类的实例用于从原始字节流中提取消息。
它旨在用于从不保留消息边界的传输中读取的数据。这种传输的一个典型示例是 TCP。
exceptionTooSmallException
parse(data)
尝试从原始字节流中提取消息。
数据参数是从输入流中新读取的 python 字节。
返回提取的消息的有序列表。它可以是一个空列表。
不产生完整消息的其余数据保存在内部,并在更多数据出现时使用。即下次再次调用此方法时。
try_parse(q)
尝试从给定的字节中提取消息。
这是子类的覆盖点。
此方法尝试从参数给出的字节中提取消息。
如果给定的数据不足以提取完整的消息,但如果以后有更多的数据,仍然有机会提取消息,则会引发 TooSmallException。
子类列表:
ryu.lib.packet.bgp.StreamParser
协议头类
Packet Base Class
class ryu.lib.packet.packet_base.PacketBase
协议(以太网、ipv4 等)标头的基类。
classmethod get_packet_type(type_)
每个协议的字典式获取方法。
为方便协议实施者而提供。仅限内部使用。
classmethod parser(buf)
解码协议标头。
此方法仅在解码数据包时使用。
在字节数组 buf 中以偏移量 0 处解码协议标头。返回以下三个对象。
- 用于描述已解码标头的对象。
- 一个适用于数据包其余部分的 packet_base.PacketBase子类。当数据包的其余部分应被视为原始有效负载时None。
- 数据包的其余部分。
classmethodregister_packet_type(cls_, type_)
每协议类似字典的集合方法。
为方便协议实施者而提供。仅限内部使用。
serialize(payload, prev)
编码协议头。
此方法仅在对数据包进行编码时使用。
编码协议头。 返回包含标头的字节数组。
有效载荷是将紧跟此标头的数据包的其余部分。
prev 是外部协议头的 packet_base.PacketBase 子类。 如果当前标头是最外层,则 prev 为 None。 例如,对于 tcp.serialize,prev 是 ipv4 或 ipv6。
ARP
class ryu.lib.packet.arp.arp(hwtype=1, proto=2048, hlen=6, plen=4, opcode=1, src_mac=‘ff:ff:ff:ff:ff:ff’, src_ip=‘0.0.0.0’, dst_mac=‘ff:ff:ff:ff:ff:ff’, dst_ip=‘0.0.0.0’)
ARP (RFC 826) 标头编码器/解码器类。
一个实例至少具有以下属性。 它们中的大多数与在线对应物相同,但按主机字节顺序排列。 IPv4 地址表示为类似“192.0.2.1”的字符串。 MAC 地址表示为字符串,如 ‘08:60:6e:7f:74:e7’。 init 按此顺序获取相应的参数。
- hwtype 硬件地址.
- proto 协议地址.
- hlen 每个硬件地址的字节长度。
- plen 每个协议地址的字节长度。
- opcode 操作代码。
- src_mac 发件人的硬件地址。 ‘08:60:6e:7f:74:e7’
- src_ip 发送方的协议地址。 ‘192.0.2.1’
- dst_mac 目标的硬件地址。 ‘00:00:00:00:00:00’
- dst_ip 目标的协议地址。 ‘192.0.2.2’
classmethodparser(buf)
解码协议头。
此方法仅在解码数据包时使用。
解码字节数组 buf 中偏移量 0 处的协议头。 返回以下三个对象。
描述解码后的标头的对象。
适合于数据包其余部分的 packet_base.PacketBase 子类。 当数据包的其余部分应被视为原始有效负载时,无。
包的其余部分。
serialize(payload, prev)
编码协议头。
此方法仅在对数据包进行编码时使用。
编码协议头。 返回包含标头的字节数组。
有效载荷是将紧跟此标头的数据包的其余部分。
prev 是外部协议头的 packet_base.PacketBase 子类。 如果当前标头是最外层,则 prev 为 None。 例如,对于 tcp.serialize,prev 是 ipv4 或 ipv6。
ryu.lib.packet.arp.arp_ip(opcode, src_mac, src_ip, dst_mac, dst_ip)
用于以太网的 IPv4 ARP 的便捷包装器。
这等效于以下代码。
arp(ARP_HW_TYPE_ETHERNET, ether.ETH_TYPE_IP, 6, 4, opcode, src_mac, src_ip, dst_mac, dst_ip)
BFD
BFD 控制数据包解析器/序列化程序
[RFC 5880]BFD 控制数据包格式:
可选的身份验证部分可能以下列类型格式存在:
简单密码验证部分的格式:
密钥 MD5 和细致的密钥 MD5 身份验证部分的格式:
键控 SHA1 和细致的键控 SHA1 身份验证部分的格式:
(这里挖个坑,暂时还没用到)
BGP
(这里挖个坑,暂时还没用到)
BMP
(这里挖个坑,暂时还没用到)
BPDU
(这里挖个坑,暂时还没用到)
CFM
(这里挖个坑,暂时还没用到)
DHCP
(这里挖个坑,暂时还没用到)
DHCP6
(这里挖个坑,暂时还没用到)
Ethernet
class ryu.lib.packet.ethernet.ethernet(dst=‘ff:ff:ff:ff:ff:ff’, src=‘00:00:00:00:00:00’, ethertype=2048)
以太网报头编码器/解码器类。
一个实例至少具有以下属性。 MAC 地址表示为字符串,如 ‘08:60:6e:7f:74:e7’。 init 按此顺序获取相应的参数。
- dst 目的地址 ‘ff:ff:ff:ff:ff:ff’
- src 源地址 ‘08:60:6e:7f:74:e7’
- ethertype 以太类型 0x0800
classmethod get_packet_type(type_)
以太网 IEEE802.3 长度/类型字段 (self.ethertype) 的覆盖方法。
如果 Length/Type 字段的值小于或等于 1500 十进制(05DC 十六进制),则表示长度解释并传递给 LLC 子层。
classmethod parser(buf)
解码协议头。
此方法仅在解码数据包时使用。
解码字节数组 buf 中偏移量 0 处的协议头。 返回以下三个对象。
- 描述解码后的标头的对象。
- 适合于数据包其余部分的 packet_base.PacketBase 子类。 当数据包的其余部分应被视为原始有效负载时None。
- 包的其余部分。
serialize(payload, prev)
编码协议头。
此方法仅在对数据包进行编码时使用。
编码协议头。 返回包含标头的字节数组。
有效载荷是将紧跟此标头的数据包的其余部分。
prev 是外部协议头的 packet_base.PacketBase 子类。 如果当前标头是最外层,则 prev 为 None。 例如,对于 tcp.serialize,prev 是 ipv4 或 ipv6。
Geneve
(这里挖个坑,暂时还没用到)
GRE
(这里挖个坑,暂时还没用到)
ICMP
class ryu.lib.packet.icmp.TimeExceeded(data_len=0, data=None)