Skip to content

OpenFlowV1.0 in Ryu

KANEKO Yoshihiro edited this page May 8, 2013 · 2 revisions

OpenFlow V1.0 messages

Controller-to-Switch Messages

Ryu application can send these messages to the switch.

Handshake

The controller sends OFPFeatureRequest to the switch upon session establishment.
OFPFeatureRequest message is handled by Ryu framework, so Ryu application does not need to process it typically.

OFPFeaturesRequest

class OFPFeaturesRequest(MsgBase):
    def __init__(self, datapath):
        super(OFPFeaturesRequest, self).__init__(datapath)
parameter description
datapath Instance of ryu.controller.controller.Datapath

OFPSwitchFeatures

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
OFPC_FLOW_STATS
OFPC_TABLE_STATS
OFPC_PORT_STATS
OFPC_STP
OFPC_RESERVED
OFPC_IP_REASM
OFPC_QUEUE_STATS
OFPC_ARP_MATCH_IP
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
ports An array of OFPPhyPort to describe all the physical ports

For more details, see section of 5.3.1 of the OpenFlow spec.

Example:

    def send_features_request(self, datapath):
        ofp_parser = datapath.ofproto_parser

        req = ofp_parser.OFPFeaturesRequest(datapath)
        datapath.send_msg(req)

    @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)

Switch Configuration

The controller sends OFPSetConfig to set configuration parameters, and sends OFPGetConfigRequest to query configuration parameters in the switch.

OFPSetConfig

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

OFPGetConfigRequest

class OFPGetConfigRequest(MsgBase):
    def __init__(self, datapath):
        super(OFPGetConfigRequest, self).__init__(datapath)
parameter description
datapath Instance of ryu.controller.controller.Datapath

OFPGetConfigReply

attribute description
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)

    def send_get_config_request(self, datapath):
        ofp_parser = datapath.ofproto_parser

        req = ofp_parser.OFPGetConfigRequest(datapath)
        datapath.send_msg(req)

    @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)

Modify State Messages

Modify Flow Entry Message

The controller sends OFPFlowMod to modify the flow table.

OFPFlowMod

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
out_group For OFPFC_DELETE* commands, require matching entries to include this as an output group
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)

Port Modification Message

The controller sends OFPPortMod to modify the behavior of the physical port.

OFPPortMod

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_HD | ofp.OFPPF_100MB_FD |
                       ofp.OFPPF_1GB_FD | ofp.OFPPF_COPPER |
                       ofp.OFPPF_AUTONEG | ofp.OFPPF_PAUSE |
                       ofp.OFPPF_PAUSE_ASYM))
        datapath.send_msg(req)

Queue Configuration Message

The controller uses OFPQueueGetConfigRequest to query the switch for configured queues on a port.

OFPQueueGetConfigRequest

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

OFPQueueGetConfigReply

attribute description
port Port which was queried
queues An array of OFPPacketQueue

For more details, see section of 5.3.4 of the OpenFlow spec.

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)

    @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)

Read State Messages

Description Statistics

The controller uses OFPDescStatsRequest to query description of the OpenFlow switch.

OFPDescStatsRequest

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

OFPDescStatsReply

attribute description
body Instance of OFPDescStats

For more details, see section of 5.3.5 of the OpenFlow spec.

Example:

    def send_desc_stats_request(self, datapath):
        ofp_parser = datapath.ofproto_parser

        req = ofp_parser.OFPDescStatsRequest(datapath, 0)
        datapath.send_msg(req)

    @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)

Individual Flow Statistics

The controller uses OFPFlowStatsRequest to query individual flow statistics.

OFPFlowStatsRequest

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

OFPFlowStatsReply

attribute description
body Instance of OFPFlowStats

For more details, see section of 5.3.5 of the OpenFlow spec.

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)

    @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)

Aggregate Flow Statistics

The controller uses OFPFlowStatsRequest to query aggregate flow statistics.

OFPAggregateStatsRequest

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

OFPAggregateStatsReply

attribute description
body Instance of OFPAggregateStats

For more details, see section of 5.3.5 of the OpenFlow spec.

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)

    @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)

Table Statistics

The controller uses OFPTableStatsRequest to query flow table statistics.

OFPTableStatsRequest

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

OFPTableStatsReply

attribute description
body Instance of OFPTableStats

For more details, see section of 5.3.5 of the OpenFlow spec.

Example:

    def send_table_stats_request(self, datapath):
        ofp_parser = datapath.ofproto_parser

        req = ofp_parser.OFPTableStatsRequest(datapath, 0)
        datapath.send_msg(req)

    @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)

Port Statistics

The controller uses OFPPortStatsRequest to query information about physical port.

OFPPortStatsRequest

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

OFPPortStatsReply

attribute description
body Instance of OFPPortStats

For more details, see section of 5.3.5 of the OpenFlow spec.

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)

    @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)

Queue Statistics

The controller uses OFPQueueStatsRequest to query statistics of one or more ports.

OFPQueueStatsRequest

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

OFPQueueStatsReply

attribute description
body Instance of OFPQueueStats

For more details, see section of 5.3.5 of the OpenFlow spec.

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)

    @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)

Send Packet Message

The controller uses OFPPacketOut to send a packet out through the switch.

OFPPacketOut

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 or OFPP_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)

Barrier Message

The switch responds to OFPBarrierRequest with OFPBarrierReply with the xid of the request, when a processing of all previously received messages was finished.

OFPBarrierRequest

class OFPBarrierRequest(MsgBase):
    def __init__(self, datapath):
        super(OFPBarrierRequest, self).__init__(datapath)
parameter description
datapath Instance of ryu.controller.controller.Datapath

OFPBarrierReply

This class has no special attribute.

Example:

    def send_barrier_request(self, datapath):
        ofp = datapath.ofproto
        ofp_parser = datapath.ofproto_parser

        req = ofp_parser.OFPBarrierRequest(datapath)
        datapath.send_msg(req)

    @set_ev_cls(ofp_event.EventOFPBarrierReply, MAIN_DISPATCHER)
    def barrier_reply_handler(self, ev):
        self.logger.debug('OFPBarrierReply received')

Asynchronous Messages

These messages are sent from the switch, and Ryu application can handle these as an event.

Packet-In Message

The switch sends the packet that received to the controller by OFPPacketIn.

OFPPacketIn

attribute description
buffer_id ID assigned by datapath
total_len Full length of frame
in_port Port on which frame was received
reason Reason packet is being sent
OFPR_NO_MATCH
OFPR_ACTION
data Ethernet frame

For more details, see section of 5.4.1 of the OpenFlow spec.

Example:

    @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))

Flow Removed Message

When flows time out, the switch notifies controller with OFPFlowRemoved.

OFPFlowRemoved

attribute description
cookie Opaque controller-issued identifier
priority Priority level of flow entry
reason One of the following values
OFPRR_IDLE_TIMEOUT
OFPRR_HARD_TIMEOUT
OFPRR_DELETE
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
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 of the OpenFlow spec.

Example:

    @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)

Port Status Message

The switch notifies controller of change of physical ports.

OFPPortStatus

attribute description
reason One of the following values
OFPPR_ADD
OFPPR_DELETE
OFPPR_MODIFY
desc An instance of OFPPhyPort

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)

Error Message

The switch notifies controller of problems by OFPErrorMsg.

OFPErrorMsg

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.

Type Code
OFPET_HELLO_FAILED OFPHFC_INCOMPATIBLE
OFPHFC_EPERM
OFPET_BAD_REQUEST 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
OFPET_BAD_ACTION 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
OFPET_FLOW_MOD_FAILED OFPFMFC_ALL_TABLES_FULL
OFPFMFC_OVERLAP
OFPFMFC_EPERM
OFPFMFC_BAD_EMERG_TIMEOUT
OFPFMFC_BAD_COMMAND
OFPFMFC_UNSUPPORTED
OFPET_PORT_MOD_FAILED OFPPMFC_BAD_PORT
OFPPMFC_BAD_HW_ADDR
OFPET_QUEUE_OP_FAILED OFPQOFC_BAD_PORT
OFPQOFC_BAD_QUEUE
OFPQOFC_EPERM

For more details, see section of 5.4.4 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))

Symmetric Messages

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.

Hello

OFPHello 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.

OFPHello

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)

Echo Request

OFPEchoRequest is sent to request an echo reply.
OFPEchoRequest message is handled by Ryu framework, so Ryu application does not need to process it typically.

OFPEchoRequest

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))

Echo Reply

When OFPEchoRequest is received, you must return OFPEchoReply.

OFPEchoReply

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))

OpenFlow Matchs

OpenFlow Match structure is defined in 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

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.

OFPActionOutput

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

OFPActionVlanVid

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

OFPActionVlanPcp

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

OFPActionStripVlan

This action indicates strips the 802.1q header.

class OFPActionStripVlan(OFPAction):
    def __init__(self):
        super(OFPActionStripVlan, self).__init__()

OFPActionSetDlSrc

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

OFPActionSetDlDst

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

OFPActionSetNwSrc

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

OFPActionSetNwDst

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

OFPActionSetNwTos

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)

OFPActionSetTpSrc

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

OFPActionSetTpDst

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

OFPActionEnqueue

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

Nicira Extensions

Ryu supports Nicira Extensions of Open vSwitch, too.

Asymmetric Messages

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

Controller-to-Switch Messages

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

Actions

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
Clone this wiki locally