-
Notifications
You must be signed in to change notification settings - Fork 0
OpenFlow in Ryu
Work in progress
The communication processing and a handling of the foundational OpenFlow protocol, e.g. hello, echo, is implemented in Ryu framework. A user Ryu application can implement a handling of necessary OpenFlow event.
An event handler is called with an event object as an argument. The event
object is representation of the OpenFlow message which Ryu received from
OpenFlow switch. The object is a subclass of
ryu.controller.ofp_event.EventOFPMsgBase
class.
class EventOFPMsgBase(event.EventBase):
def __init__(self, msg):
super(EventOFPMsgBase, self).__init__()
self.msg = msg
Each event class is created dynamically from the corresponding OpenFlow message class. Because of that, you cannot find the code of an event class explicitly.
The name of event class is 'Event' + corresponding message class name.
For example, the event class for OFPPacketIn
message is EventOFPPacketIn
.
The msg
attribute of the event class holds the message class instance
which created it.
Each OpenFlow message class is a subclass of
ryu.ofproto.ofproto_parser.MsgBase
class. The MsgBase class is defined as
follows, so every OpenFlow message class have those attributes.
class MsgBase(object):
def __init__(self, datapath):
self.datapath = datapath
self.version = None
self.msg_type = None
self.msg_len = None
self.xid = None
self.buf = None
Attribute | Description |
---|---|
datapath | A ryu.controller.controller.Datapath instance associated with the OpenFlow switch |
version | OpenFlow protocol version |
msg_type | Type of OpenFlow message |
msg_len | Length of the message |
xid | Transaction id |
buf | Raw data |
The following example is handling EventOFPPacketIn and sending OFPPacketOut.
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
class MySwitch(app_manager.RyuApp):
def __init__(self, *args, **kwargs):
super(MySwitch, self).__init__(*args, **kwargs)
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
ofp_parser = dp.ofproto_parser
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)]
out = ofp_parser.OFPPacketOut(
datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port,
actions=actions)
dp.send_msg(out)
Symmetric messages are sent from both of the switch and the controller. Ryu application can handle them as an event, and also send them to the switch.
[OF1.0, OF1.2, OF1.3]
This message is exchanged between the switch and controller upon connection
startup.
OFPHello message is handled by Ryu framework, so Ryu application does not need to process it typically.
This class has no special attribute.
Example:
@set_ev_cls(ofp_event.EventOFPHello, HANDSHAKE_DISPATCHER)
def hello_handler(self, ev):
self.logger.debug('OFPHello received: OF version=0x%02x', msg.version)
[OF1.0, OF1.2, OF1.3]
This message is sent to request an echo reply.
OFPEchoRequest message is handled by Ryu framework, so Ryu application does not need to process it typically.
Attribute | Description |
---|---|
data | An arbitrary length data |
Example:
@set_ev_cls(ofp_event.EventOFPEchoRequest,
[HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
def echo_request_handler(self, ev):
msg = ev.msg
self.logger.debug('OFPEchoRequest received: data=%s',
utils.hex_array(msg.data))
[OF1.0, OF1.2, OF1.3]
When an echo request is received, you must return an echo reply.
attribute | description |
---|---|
data | The unmodified data of an echo request message |
Example:
@set_ev_cls(ofp_event.EventOFPEchoReply,
[HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
def echo_reply_handler(self, ev):
msg = ev.msg
self.logger.debug('OFPEchoReply received: data=%s',
utils.hex_array(msg.data))
[OF1.0, OF1.2, OF1.3]
The switch notifies controller of problems by this message.
Attribute | Description |
---|---|
type | High level type of error |
code | Details depending on the type |
data | Variable length data depending on the type and code |
Types and codes are defined in ryu.ofproto.ofproto_v1_0
, ryu.ofproto.ofproto_v1_2
, ryu.ofproto.ofproto_v1_3
.
Type | Code |
---|---|
OFPET_HELLO_FAILED |
OFPHFC_INCOMPATIBLE OFPHFC_EPERM |
OFPET_BAD_REQUEST |
[OF1.0] OFPBRC_BAD_VERSION OFPBRC_BAD_TYPE OFPBRC_BAD_STAT OFPBRC_BAD_VENDOR OFPBRC_BAD_SUBTYPE OFPBRC_EPERM OFPBRC_BAD_LEN OFPBRC_BUFFER_EMPTY OFPBRC_BUFFER_UNKNOWN |
[OF1.2] OFPBRC_BAD_VERSION OFPBRC_BAD_TYPE OFPBRC_BAD_STAT OFPBRC_BAD_EXPERIMENTER OFPBRC_BAD_EXT_TYPE OFPBRC_EPERM OFPBRC_BAD_LEN OFPBRC_BUFFER_EMPTY OFPBRC_BUFFER_UNKNOWN OFPBRC_BAD_TABLE_ID OFPBRC_IS_SLAVE OFPBRC_BAD_PORT OFPBRC_BAD_PACKET |
|
[OF1.3] OFPBRC_BAD_VERSION OFPBRC_BAD_TYPE OFPBRC_BAD_MULTIPART OFPBRC_BAD_EXPERIMENTER OFPBRC_BAD_EXT_TYPE OFPBRC_EPERM OFPBRC_BAD_LEN OFPBRC_BUFFER_EMPTY OFPBRC_BUFFER_UNKNOWN OFPBRC_BAD_TABLE_ID OFPBRC_IS_SLAVE OFPBRC_BAD_PORT OFPBRC_BAD_PACKET OFPBRC_MULTIPART_BUFFER_OVERFLOW |
|
OFPET_BAD_ACTION |
[OF1.0] OFPBAC_BAD_TYPE OFPBAC_BAD_LEN OFPBAC_BAD_VENDOR OFPBAC_BAD_VENDOR_TYPE OFPBAC_BAD_OUT_PORT OFPBAC_BAD_ARGUMENT OFPBAC_EPERM OFPBAC_TOO_MANY OFPBAC_BAD_QUEUE |
[OF1.2, OF1.3] OFPBAC_BAD_TYPE OFPBAC_BAD_LEN OFPBAC_BAD_EXPERIMENTER OFPBAC_BAD_EXP_TYPE OFPBAC_BAD_OUT_PORT OFPBAC_BAD_ARGUMENT OFPBAC_EPERM OFPBAC_TOO_MANY OFPBAC_BAD_QUEUE OFPBAC_BAD_OUT_GROUP OFPBAC_MATCH_INCONSISTENT OFPBAC_UNSUPPORTED_ORDER OFPBAC_BAD_TAG OFPBAC_BAD_SET_TYPE OFPBAC_BAD_SET_LEN OFPBAC_BAD_SET_ARGUMENT |
|
[OF1.2, OF1.3] OFPET_BAD_INSTRUCTION |
OFPBIC_UNKNOWN_INST OFPBIC_UNSUP_INST OFPBIC_BAD_TABLE_ID OFPBIC_UNSUP_METADATA OFPBIC_UNSUP_METADATA_MASK OFPBIC_BAD_EXPERIMENTER OFPBIC_BAD_EXP_TYPE OFPBIC_BAD_LEN OFPBIC_EPERM |
[OF1.2, OF1.3] OFPET_BAD_MATCH |
OFPBMC_BAD_TYPE OFPBMC_BAD_LEN OFPBMC_BAD_TAG OFPBMC_BAD_DL_ADDR_MASK OFPBMC_BAD_NW_ADDR_MASK OFPBMC_BAD_WILDCARDS OFPBMC_BAD_FIELD OFPBMC_BAD_VALUE OFPBMC_BAD_MASK OFPBMC_BAD_PREREQ OFPBMC_DUP_FIELD OFPBMC_EPERM |
OFPET_FLOW_MOD_FAILED |
[OF1.0] OFPFMFC_ALL_TABLES_FULL OFPFMFC_OVERLAP OFPFMFC_EPERM OFPFMFC_BAD_EMERG_TIMEOUT OFPFMFC_BAD_COMMAND OFPFMFC_UNSUPPORTED |
[OF1.2, OF1.3] OFPFMFC_UNKNOWN OFPFMFC_TABLE_FULL OFPFMFC_BAD_TABLE_ID OFPFMFC_OVERLAP OFPFMFC_EPERM OFPFMFC_BAD_TIMEOUT OFPFMFC_BAD_COMMAND OFPFMFC_BAD_FLAGS |
|
[OF1.2, OF1.3] OFPET_GROUP_MOD_FAILED |
OFPGMFC_GROUP_EXISTS OFPGMFC_INVALID_GROUP OFPGMFC_WEIGHT_UNSUPPORTED OFPGMFC_OUT_OF_GROUPS OFPGMFC_OUT_OF_BUCKETS OFPGMFC_CHAINING_UNSUPPORTED OFPGMFC_WATCH_UNSUPPORTED OFPGMFC_LOOP OFPGMFC_UNKNOWN_GROUP OFPGMFC_CHAINED_GROUP OFPGMFC_BAD_TYPE OFPGMFC_BAD_COMMAND OFPGMFC_BAD_BUCKET OFPGMFC_BAD_WATCH OFPGMFC_EPERM |
OFPET_PORT_MOD_FAILED |
[OF1.0] OFPPMFC_BAD_PORT OFPPMFC_BAD_HW_ADDR |
[OF1.2, OF1.3] OFPPMFC_BAD_PORT OFPPMFC_BAD_HW_ADDR OFPPMFC_BAD_CONFIG OFPPMFC_BAD_ADVERTISE OFPPMFC_EPERM |
|
[OF1.2, OF1.3] OFPET_TABLE_MOD_FAILED |
OFPTMFC_BAD_TABLE OFPTMFC_BAD_CONFIG OFPTMFC_EPERM |
OFPET_QUEUE_OP_FAILED |
OFPQOFC_BAD_PORT OFPQOFC_BAD_QUEUE OFPQOFC_EPERM |
[OF1.2, OF1.3] OFPET_SWITCH_CONFIG_FAILED |
OFPSCFC_BAD_FLAGS OFPSCFC_BAD_LEN OFPQCFC_EPERM |
[OF1.2, OF1.3] OFPET_ROLE_REQUEST_FAILED |
OFPRRFC_STALE OFPRRFC_UNSUP OFPRRFC_BAD_ROLE |
[OF1.3] OFPET_METER_MOD_FAILED |
OFPMMFC_UNKNOWN OFPMMFC_METER_EXISTS OFPMMFC_INVALID_METER OFPMMFC_UNKNOWN_METER OFPMMFC_BAD_COMMAND OFPMMFC_BAD_FLAGS OFPMMFC_BAD_RATE OFPMMFC_BAD_BURST OFPMMFC_BAD_BAND OFPMMFC_BAD_BAND_VALUE OFPMMFC_OUT_OF_METERS OFPMMFC_OUT_OF_BANDS |
[OF1.3] OFPET_TABLE_FEATURES_FAILED |
OFPTFFC_BAD_TABLE OFPTFFC_BAD_METADATA OFPTFFC_BAD_TYPE OFPTFFC_BAD_LEN OFPTFFC_BAD_ARGUMENT OFPTFFC_EPERM |
[OF1.2, OF1.3] OFPET_EXPERIMENTER |
N/A |
For more details, see section of 5.4.4 (OF1.0), A.4.4 (OF1.2, OF1.3) of the OpenFlow spec.
Example:
@set_ev_cls(ofp_event.EventOFPErrorMsg,
[HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
def error_msg_handler(self, ev):
msg = ev.msg
self.logger.debug('OFPErrorMsg received: type=0x%02x code=0x%02x '
'message=%s',
msg.type, msg.code, utils.hex_array(msg.data))
These messages are sent from the switch, and Ryu application can handle these as an event.
[OF1.0, OF1.2, OF1.3]
A features reply that specifies the capabilities supported by the switch.
attribute | description |
---|---|
datapath_id | Datapath unique ID (64bit integer) |
n_buffers | Max packets buffered at once |
n_tables | Number of tables supported by datapath |
capabilities | Bitmap of supported features |
[OF1.0] OFPC_FLOW_STATS OFPC_TABLE_STATS OFPC_PORT_STATS OFPC_STP OFPC_RESERVED OFPC_IP_REASM OFPC_QUEUE_STATS OFPC_ARP_MATCH_IP |
|
[OF1.2, OF1.3] OFPC_FLOW_STATS OFPC_TABLE_STATS OFPC_PORT_STATS OFPC_GROUP_STATS OFPC_IP_REASM OFPC_QUEUE_STATS OFPC_PORT_BLOCKED |
|
[OF1.0] actions |
Bitmap of supported actions uses the following values as the number of bits to shift left |
OFPAT_OUTPUT OFPAT_SET_VLAN_VID OFPAT_SET_VLAN_PCP OFPAT_STRIP_VLAN OFPAT_SET_DL_SRC OFPAT_SET_DL_DST OFPAT_SET_NW_SRC OFPAT_SET_NW_DST OFPAT_SET_NW_TOS OFPAT_SET_TP_SRC OFPAT_SET_TP_DST OFPAT_ENQUEUE |
|
[OF1.2, OF1.3] reserved |
N/A |
[OF1.0, OF1.2] ports |
An array of OFPPhyPort [OF1.0], OFPPort [OF1.2] to describe all the physical ports |
For more details, see section of 5.3.1 (OF1.0), A.3.1 (OF1.2, OF1.3) of the OpenFlow spec.
Example [OF1.0]:
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
msg = ev.msg
ports = []
for _port_no, port in msg.ports.items():
ports.append('no=%s name=%s' % (port.port_no,
port.name.rstrip("\\0")))
self.logger.debug('OFPSwitchFeatures received: '
'datapath_id = %016x n_buffers = %d '
'n_tables = %d capabilities = %08x '
'actions = %08x ports = %s',
msg.datapath_id, msg.n_buffers, msg.n_tables,
msg.capabilities, msg.actions, ports)
[OF1.0, OF1.2, OF1.3]
The switch notifies controller of change of physical ports.
attribute | description |
---|---|
reason | One of the following values |
OFPPR_ADD OFPPR_DELETE OFPPR_MODIFY |
|
desc | An instance of OFPPhyPort (OF1.0), OFPPort (OF1.2, OF1.3) |
Example:
@set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
def port_status_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
if msg.reason == ofp.OFPPR_ADD:
self.logger.debug('OFPPortStatus received: port add: %s',
msg.desc)
elif msg.reason == ofp.OFPPR_DELETE:
self.logger.debug('OFPPortStatus received: port delete: %s',
msg.desc)
elif msg.reason == ofp.OFPPR_MODIFY:
self.logger.debug('OFPPortStatus received: port modify: %s',
msg.desc)
else:
self.logger.debug('OFPPortStatus received: unknown reason: %s',
msg.desc)
[OF1.0, OF1.2, OF1.3]
The switch sends the packet that received to the controller by this message.
attribute | description |
---|---|
buffer_id | ID assigned by datapath |
total_len | Full length of frame |
[OF1.0] in_port |
Port on which frame was received |
reason | Reason packet is being sent |
[OF1.0] OFPR_NO_MATCH OFPR_ACTION |
|
[OF1.2, OF1.3] OFPR_NO_MATCH OFPR_ACTION OFPR_INVALID_TTL |
|
[OF1.2, OF1.3] table_id |
ID of the table that was looked up |
[OF1.2, OF1.3] match |
Instance of OFPMatch
|
data | Ethernet frame |
For more details, see section of 5.4.1 (OF1.0), A.4.1 (OF1.2, OF1.3) of the OpenFlow spec.
Example [OF1.0]:
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
if msg.reason == ofp.OFPR_NO_MATCH:
reason = 'NO MATCH'
elif msg.reason == ofp.OFPR_ACTION:
reason = 'ACTION'
else:
reason = 'unknown'
self.logger.debug('OFPPacketIn received: '
'buffer_id=%x len=%d in_port=%d reason=%s data=%s',
msg.buffer_id, msg.total_len, msg.in_port, reason,
utils.hex_array(msg.data))
[OF1.0, OF1.2, OF1.3]
The switch responds to a configuration request with this message.
attribute | description |
---|---|
flags | One of the following configuration flags |
[OF1.0] OFPC_FRAG_NORMAL OFPC_FRAG_DROP OFPC_FRAG_REASM OFPC_FRAG_NX_MATCH OFPC_FRAG_MASK |
|
[OF1.2] OFPC_FRAG_NORMAL OFPC_FRAG_DROP OFPC_FRAG_REASM OFPC_FRAG_MASK OFPC_INVALID_TTL_TO_CONTROLLER |
|
[OF1.3] OFPC_FRAG_NORMAL OFPC_FRAG_DROP OFPC_FRAG_REASM OFPC_FRAG_MASK |
|
miss_send_len | Max bytes of new flow that datapath should send to the controller |
For more details, see section of 5.3.2 (OF1.0), A.3.2 (OF1.2, OF1.3) of the OpenFlow spec.
Example [OF1.0]:
@set_ev_cls(ofp_event.EventOFPGetConfigReply, MAIN_DISPATCHER)
def get_config_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
if msg.flags == ofp.OFPC_FRAG_NORMAL:
flags = 'NORMAL'
elif msg.flags == ofp.OFPC_FRAG_DROP:
flags = 'DROP'
elif msg.flags == ofp.OFPC_FRAG_REASM:
flags = 'REASM'
elif msg.flags == ofp.OFPC_FRAG_NX_MATCH:
flags = 'NX MATCH'
elif msg.flags == ofp.OFPC_FRAG_MASK:
flags = 'MASK'
else:
flags = 'unknown'
self.logger.debug('OFPGetConfigReply received: '
'flags=%s miss_send_len=%d',
flags, msg.miss_send_len)
[OF1.0, OF1.2, OF1.3]
The switch responds to a barrier request with this message with the xid of the request, when a processing of all previously received messages was finished.
This class has no special attribute.
Example:
@set_ev_cls(ofp_event.EventOFPBarrierReply, MAIN_DISPATCHER)
def barrier_reply_handler(self, ev):
self.logger.debug('OFPBarrierReply received')
[OF1.0, OF1.2, OF1.3]
When flows time out, the switch notifies controller with this message.
attribute | description |
---|---|
cookie | Opaque controller-issued identifier |
priority | Priority level of flow entry |
reason | One of the following values |
[OF1.0] OFPRR_IDLE_TIMEOUT OFPRR_HARD_TIMEOUT OFPRR_DELETE |
|
[OF1.2, OF1.3] OFPRR_IDLE_TIMEOUT OFPRR_HARD_TIMEOUT OFPRR_DELETE OFPRR_GROUP_DELETE |
|
[OF1.2, OF1.3] table_id |
ID of the table |
duration_sec | Time flow was alive in seconds |
duration_nsec | Time flow was alive in nanoseconds beyond duration_sec |
idle_timeout | Idle timeout from original flow mod |
[OF1.2, OF1.3] hard_timeout |
Hard timeout from original flow mod |
packet_count | Number of packets that was associated with the flow |
byte_count | Number of bytes that was associated with the flow |
match | Instance of OFPMatch
|
For more details, see section of 5.4.2 (OF1.0), A.4.2 (OF1.2, OF1.3) of the OpenFlow spec.
Example [OF1.0]:
@set_ev_cls(ofp_event.EventOFPFlowRemoved, MAIN_DISPATCHER)
def flow_removed_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
if msg.reason == ofp.OFPRR_IDLE_TIMEOUT:
reason = 'IDLE TIMEOUT'
elif msg.reason == ofp.OFPRR_HARD_TIMEOUT:
reason = 'HARD TIMEOUT'
elif msg.reason == ofp.OFPRR_DELETE:
reason = 'DELETE'
else:
reason = 'unknown'
self.logger.debug('OFPFlowRemoved received: '
'match=%s cookie=%d priority=%d reason=%s '
'duration_sec=%d duration_nsec=%d '
'idle_timeout=%d packet_count=%d byte_count=%d',
msg.match, msg.cookie, msg.priority, reason,
msg.duration_sec, msg.duration_nsec,
msg.idle_timeout, msg.packet_count, msg.byte_count)
[OF1.0, OF1.2, OF1.3]
The switch responds to a queue configuration request with this message.
attribute | description |
---|---|
port | Port which was queried |
queues | An array of OFPPacketQueue
|
For more details, see section of 5.3.4 (OF1.0), A.3.4 (OF1.2, OF1.3) of the OpenFlow spec.
Example:
@set_ev_cls(ofp_event.EventOFPQueueGetConfigReply, MAIN_DISPATCHER)
def queue_get_config_reply_handler(self, ev):
msg = ev.msg
self.logger.debug('OFPQueueGetConfigReply received: port=%s queues=%s',
msg.port, msg.queues)
[OF1.0, OF1.2, OF1.3]
Description of the OpenFlow switch.
attribute | description |
---|---|
body | Instance of OFPDescStats
|
For more details, see section of 5.3.5 (OF1.0), A.3.5.1 (OF1.2, OF1.3) of the OpenFlow spec.
Example:
@set_ev_cls(ofp_event.EventOFPDescStatsReply, MAIN_DISPATCHER)
def desc_stats_reply_handler(self, ev):
msg = ev.msg
body = msg.body
self.logger.debug('OFPDescStatsReply received: '
'mfr_desc=%s hw_desc=%s sw_desc=%s '
'serial_num=%s dp_desc=%s',
body.mfr_desc, body.hw_desc, body.sw_desc,
body.serial_num, body.dp_desc)
[OF1.0, OF1.2, OF1.3]
Individual flow statistics.
attribute | description |
---|---|
body | Instance of OFPFlowStats
|
For more details, see section of 5.3.5 (OF1.0), A.3.5.2 (OF1.2, OF1.3) of the OpenFlow spec.
Example [OF1.0]:
@set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
def flow_stats_reply_handler(self, ev):
msg = ev.msg
body = msg.body
stats = []
for stat in body:
stats.append('length=%d table_id=%d match=%s '
'duration_sec=%d duration_nsec=%d '
'priority=%d idle_timeout=%d hard_timeout=%d '
'cookie=%d packet_count=%d byte_count=%d '
'actions=%s' % (stat.length, stat.table_id,
stat.match, stat.duration_sec,
stat.duration_nsec, stat.priority,
stat.idle_timeout, stat.hard_timeout,
stat.cookie, stat.packet_count,
stat.byte_count, stat.actions))
self.logger.debug('OFPFlowStatsReply received: body=%s', stats)
[OF1.0, OF1.2, OF1.3]
Aggregate flow statistics.
attribute | description |
---|---|
body | Instance of OFPAggregateStats
|
For more details, see section of 5.3.5 (OF1.0), A.3.5.3 (OF1.2, OF1.3) of the OpenFlow spec.
Example:
@set_ev_cls(ofp_event.EventOFPAggregateStatsReply, MAIN_DISPATCHER)
def aggregate_stats_reply_handler(self, ev):
msg = ev.msg
body = msg.body
stats = []
for stat in body:
stats.append('packet_count=%d byte_count=%d flow_count=%d' %
(stat.packet_count, stat.byte_count, stat.flow_count))
self.logger.debug('OFPAggregateStatsReply received: body=%s', stats)
[OF1.0, OF1.2, OF1.3]
Flow table statistics.
attribute | description |
---|---|
body | Instance of OFPTableStats
|
For more details, see section of 5.3.5 (OF1.0), A.3.5.4 (OF1.2, OF1.3) of the OpenFlow spec.
Example [OF1.0]:
@set_ev_cls(ofp_event.EventOFPTableStatsReply, MAIN_DISPATCHER)
def table_stats_reply_handler(self, ev):
msg = ev.msg
body = msg.body
stats = []
for stat in body:
stats.append('table_id=%d name=%s wildcards=0x%08x max_entries=%d '
'active_count=%d lookup_count=%d matched_count=%d' %
(stat.table_id, stat.name.rstrip("\\0"),
stat.wildcards, stat.max_entries, stat.active_count,
stat.lookup_count, stat.matched_count))
self.logger.debug('OFPTableStatsReply received: body=%s', stats)
[OF1.0, OF1.2, OF1.3]
Physical port statistics.
attribute | description |
---|---|
body | Instance of OFPPortStats
|
For more details, see section of 5.3.5 (OF1.0), A.3.5.5 (OF1.2), A.3.5.6 (OF1.3) of the OpenFlow spec.
Example [OF1.0, OF1.2]:
@set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
def port_stats_reply_handler(self, ev):
msg = ev.msg
body = msg.body
stats = []
for stat in body:
stats.append('port_no=%d rx_packets=%d tx_packets=%d '
'rx_bytes=%d tx_bytes=%d rx_dropped=%d tx_dropped=%d '
'rx_errors=%d tx_errors=%d '
'rx_frame_err=%d rx_over_err=%d rx_crc_err=%d '
'collisions=%d' % (stat.port_no, stat.rx_packets,
stat.tx_packets, stat.rx_bytes,
stat.tx_bytes, stat.rx_dropped,
stat.tx_dropped, stat.rx_errors,
stat.tx_errors, stat.rx_frame_err,
stat.rx_over_err, stat.rx_crc_err,
stat.collisions))
self.logger.debug('OFPPortStatsReply received: body=%s', stats)
[OF1.0, OF1.2, OF1.3]
Queue statistics for a port.
attribute | description |
---|---|
body | Instance of OFPQueueStats
|
For more details, see section of 5.3.5 (OF1.0), A.3.5.6 (OF1.2), A.3.5.8 (OF1.3) of the OpenFlow spec.
Example [OF1.0, OF1.2]:
@set_ev_cls(ofp_event.EventOFPQueueStatsReply, MAIN_DISPATCHER)
def queue_stats_reply_handler(self, ev):
msg = ev.msg
body = msg.body
stats = []
for stat in body:
stats.append('port_no=%d queue_id=%d '
'tx_bytes=%d tx_packets=%d tx_errors=%d' %
(stat.port_no, stat.queue_id, stat.tx_packets,
stat.tx_bytes, stat.tx_packets, stat.tx_errors))
self.logger.debug('OFPQueueStatsReply received: body=%s', stats)
[OF1.2, OF1.3]
Group counter statistics.
attribute | description |
---|---|
body | Instance of OFPGroupStats
|
For more details, see section of A.3.5.7 (OF1.2), A.3.5.9 (OF1.3) of the OpenFlow spec.
[OF1.2, OF1.3]
Group counter statistics.
attribute | description |
---|---|
body | Instance of OFPGroupDescStats
|
For more details, see section of A.3.5.8 (OF1.2), A.3.5.10 (OF1.3) of the OpenFlow spec.
[OF1.2, OF1.3]
Group features.
attribute | description |
---|---|
body | Instance of OFPGroupFeaturesStats
|
For more details, see section of A.3.5.9 (OF1.2), A.3.5.11 (OF1.3) of the OpenFlow spec.
[OF1.3]
Meter statistics.
attribute | description |
---|---|
body | Instance of OFPMeterStats
|
For more details, see section of A.3.5.12 of the OpenFlow spec.
[OF1.3]
Meter configuration.
attribute | description |
---|---|
body | Instance of OFPMeterConfigStats
|
For more details, see section of A.3.5.13 of the OpenFlow spec.
[OF1.3]
Meter features.
attribute | description |
---|---|
body | Instance of OFPMeterFeaturesStats
|
For more details, see section of A.3.5.14 of the OpenFlow spec.
Ryu application can send these messages to the switch.
The controller sends this message to the switch upon session establishment.
OFPFeatureRequest message is handled by Ryu framework, so Ryu application does not need to process it typically.
class OFPFeaturesRequest(MsgBase):
def __init__(self, datapath):
super(OFPFeaturesRequest, self).__init__(datapath)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
Example:
def send_features_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPFeaturesRequest(datapath)
datapath.send_msg(req)
The controller sends this message to query configuration parameters in the switch.
class OFPGetConfigRequest(MsgBase):
def __init__(self, datapath):
super(OFPGetConfigRequest, self).__init__(datapath)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
Example:
def send_get_config_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPGetConfigRequest(datapath)
datapath.send_msg(req)
The controller sends this message to set configuration parameters in the switch.
class OFPSetConfig(MsgBase):
def __init__(self, datapath, flags=None, miss_send_len=None):
super(OFPSetConfig, self).__init__(datapath)
self.flags = flags
self.miss_send_len = miss_send_len
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags |
One of the following configuration flags. OFPC_FRAG_NORMAL OFPC_FRAG_DROP OFPC_FRAG_REASM OFPC_FRAG_NX_MATCH OFPC_FRAG_MASK |
miss_send_len | Max bytes of new flow that datapath should send to the controller |
For more details, see section of 5.3.2 of the OpenFlow spec.
Example:
def send_set_config(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPSetConfig(datapath, ofp.OFPC_FRAG_NORMAL, 256)
datapath.send_msg(req)
The controller uses this message to send a packet out through the switch.
class OFPPacketOut(MsgBase):
def __init__(self, datapath, buffer_id=None, in_port=None, actions=None,
data=None):
super(OFPPacketOut, self).__init__(datapath)
self.buffer_id = buffer_id
self.in_port = in_port
self.actions_len = None
self.actions = actions
self.data = data
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
buffer_id | ID assigned by datapath (0xffffffff if none) |
in_port | Packet's input port (OFPP_NONE if none) |
actions | An array of OpenFlow action class which is a subclass of OFPAction
|
data | Packet data |
Example:
def send_packet_out(self, datapath, buffer_id, in_port):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)]
req = ofp_parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id,
in_port=in_port, actions=actions)
datapath.send_msg(req)
The controller sends this message to modify the flow table.
class OFPFlowMod(MsgBase):
def __init__(self, datapath, match, cookie, command,
idle_timeout=0, hard_timeout=0,
priority=ofproto_v1_0.OFP_DEFAULT_PRIORITY,
buffer_id=0xffffffff, out_port=ofproto_v1_0.OFPP_NONE,
flags=0, actions=None):
if actions is None:
actions = []
super(OFPFlowMod, self).__init__(datapath)
self.match = match
self.cookie = cookie
self.command = command
self.idle_timeout = idle_timeout
self.hard_timeout = hard_timeout
self.priority = priority
self.buffer_id = buffer_id
self.out_port = out_port
self.flags = flags
self.actions = actions
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
match | Instance of OFPMatch
|
cookie | Opaque controller-issued identifier |
command |
One of the following values. OFPFC_ADD OFPFC_MODIFY OFPFC_MODIFY_STRICT OFPFC_DELETE OFPFC_DELETE_STRICT |
idle_timeout | Idle time before discarding (seconds) |
hard_timeout | Max time before discarding (seconds) |
priority | Priority level of flow entry |
buffer_id | Buffered packet to apply to (or 0xffffffff) |
out_port | For OFPFC_DELETE* commands, require matching entries to include this as an output port |
flags |
One of the following values. OFPFF_SEND_FLOW_REM OFPFF_CHECK_OVERLAP OFPFF_EMERG |
actions | An array of OpenFlow action class which is a subclass of
OFPAction
|
For more details, see section of 5.3.3 of the OpenFlow spec.
Example:
def send_flow_mod(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
match = ofp_parser.OFPMatch(
ofp.OFPFW_ALL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_NORMAL)]
req = ofp_parser.OFPFlowMod(datapath=datapath, match=match, cookie=0,
command=ofp.OFPFC_ADD,
flags=ofp.OFPFF_SEND_FLOW_REM,
actions=actions)
datapath.send_msg(req)
The controller sends this message to modify the behavior of the physical port.
class OFPPortMod(MsgBase):
def __init__(self, datapath, port_no, hw_addr, config, mask, advertise):
super(OFPPortMod, self).__init__(datapath)
self.port_no = port_no
self.hw_addr = hw_addr
self.config = config
self.mask = mask
self.advertise = advertise
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
port_no | Port number to modify |
hw_addr | The hardware address that must be the same as hw_addr of
OFPPhyPort of OFPSwitchFeatures
|
config |
Bitmap of configuration flags. OFPPC_PORT_DOWN OFPPC_NO_STP OFPPC_NO_RECV OFPPC_NO_RECV_STP OFPPC_NO_FLOOD OFPPC_NO_FWD OFPPC_NO_PACKET_IN |
mask | Bitmap of configuration flags above to be changed |
advertise |
Bitmap of the following flags. OFPPF_10MB_HD OFPPF_10MB_FD OFPPF_100MB_HD OFPPF_100MB_FD OFPPF_1GB_HD OFPPF_1GB_FD OFPPF_10GB_FD OFPPF_COPPER OFPPF_FIBER OFPPF_AUTONEG OFPPF_PAUSE OFPPF_PAUSE_ASYM |
For more details, see section of 5.3.3 of the OpenFlow spec.
Example:
def send_port_mod(self, datapath, port):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPPortMod(
datapath=datapath, port_no=port.port_no, hw_addr=port.hw_addr,
config=ofp.OFPPC_NO_STP,
mask=(ofp.OFPPC_PORT_DOWN | ofp.OFPPC_NO_STP | ofp.OFPPC_NO_RECV |
ofp.OFPPC_NO_RECV_STP | ofp.OFPPC_NO_FLOOD |
ofp.OFPPC_NO_FWD | ofp.OFPPC_NO_PACKET_IN),
advertise=(ofp.OFPPF_10MB_FD | ofp.OFPPF_100MB_HD |
ofp.OFPPF_1GB_HD | ofp.OFPPF_COPPER |
ofp.OFPPF_AUTONEG | ofp.OFPPF_PAUSE |
ofp.OFPPF_PAUSE_ASYM))
datapath.send_msg(req)
The controller sends this message to request a berrier reply.
class OFPBarrierRequest(MsgBase):
def __init__(self, datapath):
super(OFPBarrierRequest, self).__init__(datapath)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
Example:
def send_barrier_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPBarrierRequest(datapath)
datapath.send_msg(req)
The controller uses this message to query the switch for configured queues on a port.
class OFPQueueGetConfigRequest(MsgBase):
def __init__(self, datapath, port):
super(OFPQueueGetConfigRequest, self).__init__(datapath)
self.port = port
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
port | Port to be queried |
Example:
def send_queue_get_config_request(self, datapath, port):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPQueueGetConfigRequest(datapath, port.port_no)
datapath.send_msg(req)
Description of the OpenFlow switch.
class OFPDescStatsRequest(OFPStatsRequest):
def __init__(self, datapath, flags):
super(OFPDescStatsRequest, self).__init__(datapath, flags)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Must be zero |
Example:
def send_desc_stats_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPDescStatsRequest(datapath, 0)
datapath.send_msg(req)
Flow table statistics.
class OFPTableStatsRequest(OFPStatsRequest):
def __init__(self, datapath, flags):
super(OFPTableStatsRequest, self).__init__(datapath, flags)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Must be zero |
Example:
def send_table_stats_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPTableStatsRequest(datapath, 0)
datapath.send_msg(req)
Individual flow statistics.
class OFPFlowStatsRequest(OFPFlowStatsRequestBase):
def __init__(self, datapath, flags, match, table_id, out_port):
super(OFPFlowStatsRequest, self).__init__(
datapath, flags, match, table_id, out_port)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Must be zero |
match | Instance of OFPMatch
|
table_id | ID of table to read |
out_port | Require matching entries to include this as an output port |
Example:
def send_flow_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPFlowStatsRequest(
datapath=datapath, flags=0,
match=ofp_parser.OFPMatch(
ofp.OFPFW_ALL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
table_id=0xff, out_port=ofp.OFPP_NONE)
datapath.send_msg(req)
Aggregate flow statistics.
class OFPAggregateStatsRequest(OFPFlowStatsRequestBase):
def __init__(self, datapath, flags, match, table_id, out_port):
super(OFPAggregateStatsRequest, self).__init__(
datapath, flags, match, table_id, out_port)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Must be zero |
match | Instance of OFPMatch
|
table_id | ID of table to read |
out_port | Require matching entries to include this as an output port |
Example:
def send_aggregate_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPAggregateStatsRequest(
datapath=datapath, flags=0,
match=ofp_parser.OFPMatch(
ofp.OFPFW_ALL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
table_id=0xff, out_port=ofp.OFPP_NONE)
datapath.send_msg(req)
This message is used to query information about physical port.
class OFPPortStatsRequest(OFPStatsRequest):
def __init__(self, datapath, flags, port_no):
super(OFPPortStatsRequest, self).__init__(datapath, flags)
self.port_no = port_no
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Must be zero |
port_no | Port number to read |
Example:
def send_port_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPPortStatsRequest(datapath, 0, ofp.OFPP_NONE)
datapath.send_msg(req)
This message is used to query queue statistics of one or more ports.
class OFPQueueStatsRequest(OFPStatsRequest):
def __init__(self, datapath, flags, port_no, queue_id):
super(OFPQueueStatsRequest, self).__init__(datapath, flags)
self.port_no = port_no
self.queue_id = queue_id
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Must be zero |
port_no | Port number to read |
queue_id | ID of queue to read |
Example:
def send_queue_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPQueueStatsRequest(datapath=datapath, flags=0,
port_no=ofp.OFPP_ALL,
queue_id=ofp.OFPQ_ALL)
datapath.send_msg(req)
OpenFlow Match structure is defined in
ryu.ofproto.ofproto_v1_0_parser.OFPMatch
.
class OFPMatch(collections.namedtuple('OFPMatchBase', (
'wildcards', 'in_port', 'dl_src', 'dl_dst', 'dl_vlan',
'dl_vlan_pcp', 'dl_type', 'nw_tos', 'nw_proto',
'nw_src', 'nw_dst', 'tp_src', 'tp_dst'))):
attribute | description |
---|---|
wildcards | Bitmap of wildcard flags |
in_port | Input switch port |
dl_src | Ethernet source address |
dl_dst | Ethernet destination address |
dl_vlan | Input VLAN ID |
dl_vlan_pcp | Input VLAN priority |
dl_type | Ethernet frame type |
nw_tos | IP ToS (DSCP field, 6 bits) |
nw_proto | IP protocol or lower 8 bits of ARP opcode |
nw_src | IP source address |
nw_dst | IP destination address |
tp_src | TCP/UDP source port |
tp_dst | TCP/UDP destination port |
The wildcards can be set the combination of the following flags which
is defined in ryu.ofproto.ofproto_v1_0
.
definition | description |
---|---|
OFPFW_IN_PORT | Switch input port |
OFPFW_DL_SRC | Ethernet source address |
OFPFW_DL_DST | Ethernet destination address |
OFPFW_DL_VLAN | VLAN ID |
OFPFW_DL_VLAN_PCP | VLAN priority |
OFPFW_DL_TYPE | Ethernet frame type |
OFPFW_NW_TOS | IP ToS (DSCP field, 6 bits) |
OFPFW_NW_PROTO | IP protocol |
OFPFW_TP_SRC | TCP/UDP source port |
OFPFW_TP_DST | TCP/UDP destination port |
OFPFW_ALL | Wildcard all fields |
In addition, the following definitions are used to set the source and destination netmasks.
definition | description |
---|---|
OFPFW_NW_SRC_SHIFT | Shift count to the field of an IP source address wildcard bit count |
OFPFW_NW_SRC_BITS | Bit length of an IP source address |
OFPFW_NW_SRC_MASK | Mask of the field of an IP source address wildcard bit count |
OFPFW_NW_SRC_ALL | Wildcard the entire field of the IP source address |
OFPFW_NW_DST_SHIFT | Shift count to the field of an IP destination address wildcard bit count |
OFPFW_NW_DST_BITS | Bit length of an IP destination address |
OFPFW_NW_DST_MASK | Mask of the field of an IP destination address wildcard bit count |
OFPFW_NW_DST_ALL | Wildcard the entire field of the IP destination address |
The wildcard for IP addresses is interpreted similar of the CIDR suffix.
However it is the opposite of the usual convention of the CIDR.
If a wildcard is set to "24", it means "255.0.0.0".
Example:
# Ethernet broadcast frame
dst = ryu.lib.mac.haddr_to_bin('ff:ff:ff:ff:ff:ff')
wildcards = ofp.OFPFW_ALL
wildcards &= ~(ofp.OFPFW_DL_DST)
match = ofp_parser.OFPMatch(wildcards, 0, 0, dst, 0, 0, 0, 0, 0, 0, 0, 0, 0)
# From port1 and source MAC address is '00:00:00:00:00:01'
src = ryu.lib.mac.haddr_to_bin('00:00:00:00:00:01')
wildcards = ofp.OFPFW_ALL
wildcards &= ~(ofp.OFPFW_IN_PORT | ofp.OFPFW_DL_SRC)
match = ofp_parser.OFPMatch(wildcards, 1, src, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
OpenFlow actions is defined in ryu.ofproto.ofproto_v1_0_parser
.
For more details than the following, see section of 5.2.4 of the OpenFlow spec.
This action indicates output a packet to the switch port.
class OFPActionOutput(OFPAction):
def __init__(self, port, max_len=0):
super(OFPActionOutput, self).__init__()
self.port = port
self.max_len = max_len
parameter | description |
---|---|
port | Output port |
max_len | Max length to send to controller |
This action indicates sets the 802.1q VLAN ID.
class OFPActionVlanVid(OFPAction):
def __init__(self, vlan_vid):
super(OFPActionVlanVid, self).__init__()
self.vlan_vid = vlan_vid
parameter | description |
---|---|
vlan_vid | VLAN ID |
This action indicates sets the 802.1q priority.
class OFPActionVlanPcp(OFPAction):
def __init__(self, vlan_pcp):
super(OFPActionVlanPcp, self).__init__()
self.vlan_pcp = vlan_pcp
parameter | description |
---|---|
vlan_pcp | VLAN priority |
This action indicates strips the 802.1q header.
class OFPActionStripVlan(OFPAction):
def __init__(self):
super(OFPActionStripVlan, self).__init__()
This action indicates sets the Ethernet source address.
class OFPActionSetDlSrc(OFPActionDlAddr):
def __init__(self, dl_addr):
super(OFPActionSetDlSrc, self).__init__(dl_addr)
parameter | description |
---|---|
dl_addr | Ethernet source address |
This action indicates sets the Ethernet destination address.
class OFPActionSetDlDst(OFPActionDlAddr):
def __init__(self, dl_addr):
super(OFPActionSetDlDst, self).__init__(dl_addr)
parameter | description |
---|---|
dl_addr | Ethernet destination address |
This action indicates sets the IPv4 source address.
class OFPActionSetNwSrc(OFPActionNwAddr):
def __init__(self, nw_addr):
super(OFPActionSetNwSrc, self).__init__(nw_addr)
parameter | description |
---|---|
nw_addr | IPv4 source address |
This action indicates sets the IPv4 destination address.
class OFPActionSetNwDst(OFPActionNwAddr):
def __init__(self, nw_addr):
super(OFPActionSetNwDst, self).__init__(nw_addr)
parameter | description |
---|---|
nw_addr | IPv4 destination address |
This action indicates sets the IPv4 ToS field.
class OFPActionSetNwTos(OFPAction):
def __init__(self, tos):
super(OFPActionSetNwTos, self).__init__()
self.tos = tos
parameter | description |
---|---|
tos | IP ToS (DSCP field, 6 bits) |
This action indicates sets the TCP/UDP source port.
class OFPActionSetTpSrc(OFPActionTpPort):
def __init__(self, tp):
super(OFPActionSetTpSrc, self).__init__(tp)
parameter | description |
---|---|
tp | TCP/UDP source port |
This action indicates sets the TCP/UDP destination port.
class OFPActionSetTpDst(OFPActionTpPort):
def __init__(self, tp):
super(OFPActionSetTpDst, self).__init__(tp)
parameter | description |
---|---|
tp | TCP/UDP destination port |
This action indicates outputs a packet to the queue.
class OFPActionEnqueue(OFPAction):
def __init__(self, port, queue_id):
super(OFPActionEnqueue, self).__init__()
self.port = port
self.queue_id = queue_id
parameter | description |
---|---|
port | Port that queue belongs |
queue_id | Where to enqueue the packets |
Ryu supports Nicira Extensions of Open vSwitch, too.
class NXTPacketIn(NiciraHeader):
def __init__(self, datapath, buffer_id, total_len, reason, table_id,
cookie, match_len, match, frame):
super(NXTPacketIn, self).__init__(
datapath, ofproto_v1_0.NXT_PACKET_IN)
self.buffer_id = buffer_id
self.total_len = total_len
self.reason = reason
self.table_id = table_id
self.cookie = cookie
self.match_len = match_len
self.match = match
self.frame = frame
class NXTFlowRemoved(NiciraHeader):
def __init__(self, datapath, cookie, priority, reason,
duration_sec, duration_nsec, idle_timeout, match_len,
packet_count, byte_count, match):
super(NXTFlowRemoved, self).__init__(
datapath, ofproto_v1_0.NXT_FLOW_REMOVED)
self.cookie = cookie
self.priority = priority
self.reason = reason
self.duration_sec = duration_sec
self.duration_nsec = duration_nsec
self.idle_timeout = idle_timeout
self.match_len = match_len
self.packet_count = packet_count
self.byte_count = byte_count
self.match = match
class NXFlowStatsReply(NXStatsReply):
def __init__(self, datapath):
super(NXFlowStatsReply, self).__init__(datapath)
class NXTRoleReply(NiciraHeader):
def __init__(self, datapath, role):
super(NXTRoleReply, self).__init__(
datapath, ofproto_v1_0.NXT_ROLE_REPLY)
self.role = role
class NXTSetAsyncConfig(NiciraHeader):
def __init__(self, datapath, packet_in_mask, port_status_mask,
flow_removed_mask):
super(NXTSetAsyncConfig, self).__init__(
datapath, ofproto_v1_0.NXT_SET_ASYNC_CONFIG)
self.packet_in_mask = packet_in_mask
self.port_status_mask = port_status_mask
self.flow_removed_mask = flow_removed_mask
class NXTSetPacketInFormat(NiciraHeader):
def __init__(self, datapath, packet_in_format):
super(NXTSetPacketInFormat, self).__init__(
datapath, ofproto_v1_0.NXT_SET_PACKET_IN_FORMAT)
self.format = packet_in_format
class NXTSetFlowFormat(NiciraHeader):
def __init__(self, datapath, flow_format):
super(NXTSetFlowFormat, self).__init__(
datapath, ofproto_v1_0.NXT_SET_FLOW_FORMAT)
self.format = flow_format
class NXTFlowAge(NiciraHeader):
def __init__(self, datapath):
super(NXTFlowAge, self).__init__(
datapath, ofproto_v1_0.NXT_FLOW_AGE)
class NXTFlowMod(NiciraHeader):
def __init__(self, datapath, cookie, command,
idle_timeout=0, hard_timeout=0,
priority=ofproto_v1_0.OFP_DEFAULT_PRIORITY,
buffer_id=0xffffffff, out_port=ofproto_v1_0.OFPP_NONE,
flags=0, rule=None, actions=None):
# the argument, rule, is positioned at the one before the last due
# to the layout struct nxt_flow_mod.
# Although rule must be given, default argument to rule, None,
# is given to allow other default value of argument before rule.
assert rule is not None
if actions is None:
actions = []
super(NXTFlowMod, self).__init__(datapath, ofproto_v1_0.NXT_FLOW_MOD)
self.cookie = cookie
self.command = command
self.idle_timeout = idle_timeout
self.hard_timeout = hard_timeout
self.priority = priority
self.buffer_id = buffer_id
self.out_port = out_port
self.flags = flags
self.rule = rule
self.actions = actions
class NXTFlowModTableId(NiciraHeader):
def __init__(self, datapath, set_):
super(NXTFlowModTableId, self).__init__(
datapath, ofproto_v1_0.NXT_FLOW_MOD_TABLE_ID)
self.set = set_
class NXFlowStatsRequest(NXStatsRequest):
def __init__(self, datapath, flags, out_port, match_len,
table_id):
super(NXFlowStatsRequest, self).__init__(datapath, flags,
ofproto_v1_0.NXST_FLOW)
self.out_port = out_port
self.match_len = match_len
self.table_id = table_id
class NXTRoleRequest(NiciraHeader):
def __init__(self, datapath, role):
super(NXTRoleRequest, self).__init__(
datapath, ofproto_v1_0.NXT_ROLE_REQUEST)
self.role = role
class NXTSetControllerId(NiciraHeader):
def __init__(self, datapath, controller_id):
super(NXTSetControllerId, self).__init__(
datapath, ofproto_v1_0.NXT_SET_CONTROLLER_ID)
self.controller_id = controller_id
class NXActionResubmit(NXActionResubmitBase):
def __init__(self, in_port=ofproto_v1_0.OFPP_IN_PORT):
super(NXActionResubmit, self).__init__(
ofproto_v1_0.NXAST_RESUBMIT, in_port, 0)
class NXActionResubmitTable(NXActionResubmitBase):
def __init__(self, in_port=ofproto_v1_0.OFPP_IN_PORT, table=0xff):
super(NXActionResubmitTable, self).__init__(
ofproto_v1_0.NXAST_RESUBMIT_TABLE, in_port, table)
class NXActionSetTunnel(NXActionHeader):
def __init__(self, tun_id_):
self.tun_id = tun_id_
super(NXActionSetTunnel, self).__init__(
ofproto_v1_0.NXAST_SET_TUNNEL,
ofproto_v1_0.NX_ACTION_SET_TUNNEL_SIZE)
class NXActionSetQueue(NXActionHeader):
def __init__(self, queue_id):
super(NXActionSetQueue, self).__init__(
ofproto_v1_0.NXAST_SET_QUEUE,
ofproto_v1_0.NX_ACTION_SET_QUEUE_SIZE)
self.queue_id = queue_id
class NXActionPopQueue(NXActionHeader):
def __init__(self):
super(NXActionPopQueue, self).__init__(
ofproto_v1_0.NXAST_POP_QUEUE,
ofproto_v1_0.NX_ACTION_POP_QUEUE_SIZE)
class NXActionRegMove(NXActionHeader):
def __init__(self, n_bits, src_ofs, dst_ofs, src, dst):
super(NXActionRegMove, self).__init__(
ofproto_v1_0.NXAST_REG_MOVE,
ofproto_v1_0.NX_ACTION_REG_MOVE_SIZE)
self.n_bits = n_bits
self.src_ofs = src_ofs
self.dst_ofs = dst_ofs
self.src = src
self.dst = dst
class NXActionRegLoad(NXActionHeader):
def __init__(self, ofs_nbits, dst, value):
super(NXActionRegLoad, self).__init__(
ofproto_v1_0.NXAST_REG_LOAD,
ofproto_v1_0.NX_ACTION_REG_LOAD_SIZE)
self.ofs_nbits = ofs_nbits
self.dst = dst
self.value = value
class NXActionSetTunnel64(NXActionHeader):
def __init__(self, tun_id_):
self.tun_id = tun_id_
super(NXActionSetTunnel64, self).__init__(
ofproto_v1_0.NXAST_SET_TUNNEL64,
ofproto_v1_0.NX_ACTION_SET_TUNNEL64_SIZE)
class NXActionMultipath(NXActionHeader):
def __init__(self, fields, basis, algorithm, max_link, arg,
ofs_nbits, dst):
super(NXActionMultipath, self).__init__(
ofproto_v1_0.NXAST_MULTIPATH,
ofproto_v1_0.NX_ACTION_MULTIPATH_SIZE)
self.fields = fields
self.basis = basis
self.algorithm = algorithm
self.max_link = max_link
self.arg = arg
self.ofs_nbits = ofs_nbits
self.dst = dst
class NXActionNote(NXActionHeader):
def __init__(self, note):
# should check here if the note is valid (only hex values)
pad = (len(note) + 10) % 8
if pad:
note += [0x0 for i in range(8 - pad)]
self.note = note
_len = len(note) + 10
super(NXActionNote, self).__init__(
ofproto_v1_0.NXAST_NOTE, _len)
class NXActionBundle(NXActionBundleBase):
def __init__(self, algorithm, fields, basis, slave_type, n_slaves,
ofs_nbits, dst, slaves):
super(NXActionBundle, self).__init__(
ofproto_v1_0.NXAST_BUNDLE,
algorithm, fields, basis, slave_type, n_slaves,
ofs_nbits, dst, slaves)
class NXActionBundleLoad(NXActionBundleBase):
def __init__(self, algorithm, fields, basis, slave_type, n_slaves,
ofs_nbits, dst, slaves):
super(NXActionBundleLoad, self).__init__(
ofproto_v1_0.NXAST_BUNDLE_LOAD,
algorithm, fields, basis, slave_type, n_slaves,
ofs_nbits, dst, slaves)
class NXActionAutopath(NXActionHeader):
def __init__(self, ofs_nbits, dst, id_):
super(NXActionAutopath, self).__init__(
ofproto_v1_0.NXAST_AUTOPATH,
ofproto_v1_0.NX_ACTION_AUTOPATH_SIZE)
self.ofs_nbits = ofs_nbits
self.dst = dst
self.id = id_
class NXActionOutputReg(NXActionHeader):
def __init__(self, ofs_nbits, src, max_len):
super(NXActionOutputReg, self).__init__(
ofproto_v1_0.NXAST_OUTPUT_REG,
ofproto_v1_0.NX_ACTION_OUTPUT_REG_SIZE)
self.ofs_nbits = ofs_nbits
self.src = src
self.max_len = max_len
class NXActionExit(NXActionHeader):
def __init__(self):
super(NXActionExit, self).__init__(
ofproto_v1_0.NXAST_EXIT,
ofproto_v1_0.NX_ACTION_HEADER_SIZE)
class NXActionDecTtl(NXActionHeader):
def __init__(self):
super(NXActionDecTtl, self).__init__(
ofproto_v1_0.NXAST_DEC_TTL,
ofproto_v1_0.NX_ACTION_HEADER_SIZE)
class NXActionLearn(NXActionHeader):
def __init__(self, idle_timeout, hard_timeout, priority, cookie, flags,
table_id, fin_idle_timeout, fin_hard_timeout, spec):
len_ = len(spec) + ofproto_v1_0.NX_ACTION_LEARN_SIZE
pad_len = 8 - (len_ % 8)
super(NXActionLearn, self).__init__(
ofproto_v1_0.NXAST_LEARN, len_ + pad_len)
self.idle_timeout = idle_timeout
self.hard_timeout = hard_timeout
self.priority = priority
self.cookie = cookie
self.flags = flags
self.table_id = table_id
self.fin_idle_timeout = fin_idle_timeout
self.fin_hard_timeout = fin_hard_timeout
self.spec = spec + bytearray('\x00' * pad_len)
class NXActionController(NXActionHeader):
def __init__(self, max_len, controller_id, reason):
super(NXActionController, self).__init__(
ofproto_v1_0.NXAST_CONTROLLER,
ofproto_v1_0.NX_ACTION_CONTROLLER_SIZE)
self.max_len = max_len
self.controller_id = controller_id
self.reason = reason
class NXActionFinTimeout(NXActionHeader):
def __init__(self, fin_idle_timeout, fin_hard_timeout):
super(NXActionFinTimeout, self).__init__(
ofproto_v1_0.NXAST_FIN_TIMEOUT,
ofproto_v1_0.NX_ACTION_FIN_TIMEOUT_SIZE)
self.fin_idle_timeout = fin_idle_timeout
self.fin_hard_timeout = fin_hard_timeout