-
Notifications
You must be signed in to change notification settings - Fork 0
OpenFlowV1.3 in Ryu
Ryu application can send these messages to the switch.
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 |
auxiliary_id | Identify auxiliary connections |
capabilities | Bitmap of supported features |
OFPC_FLOW_STATS OFPC_TABLE_STATS OFPC_PORT_STATS OFPC_GROUP_STATS OFPC_IP_REASM OFPC_QUEUE_STATS OFPC_PORT_BLOCKED |
|
reserved | N/A |
For more details, see section of A.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 main_switch_features_handler(self, ev):
msg = ev.msg
self.logger.debug('OFPSwitchFeatures received: '
'datapath_id=0x%016x n_buffers=%d '
'n_tables=%d auxiliary_id=%d capabilities=0x%08x',
msg.datapath_id, msg.n_buffers, msg.n_tables,
msg.auxiliary_id, msg.capabilities)
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_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_MASK |
|
miss_send_len | Max bytes of new flow that datapath should send to the controller |
For more details, see section of A.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_MASK:
flags = 'MASK'
else:
flags = 'unknown'
self.logger.debug('OFPGetConfigReply received: '
'flags=%s miss_send_len=%d',
flags, msg.miss_send_len)
The controller sends OFPTableMod to configure table state in the switch.
OFPTableMod
class OFPTableMod(MsgBase):
def __init__(self, datapath, table_id, config):
super(OFPTableMod, self).__init__(datapath)
self.table_id = table_id
self.config = config
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
table_id | ID of the table, OFPTT_ALL indicates all tables |
config | One of the following values |
OFPTC_DEPRECATED_MASK = 3 |
For more details, see section of A.3.3 of the OpenFlow spec.
Example:
def send_table_mod(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPTableMod(datapath, 1, 3)
datapath.send_msg(req)
The controller sends OFPFlowMod to modify the flow table.
OFPFlowMod
class OFPFlowMod(MsgBase):
def __init__(self, datapath, cookie, cookie_mask, table_id, command,
idle_timeout, hard_timeout, priority, buffer_id, out_port,
out_group, flags, match, instructions):
super(OFPFlowMod, self).__init__(datapath)
self.cookie = cookie
self.cookie_mask = cookie_mask
self.table_id = table_id
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.out_group = out_group
self.flags = flags
self.match = match
self.instructions = instructions
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
match | Instance of OFPMatch
|
cookie | Opaque controller-issued identifier |
cookie_mask | Mask used to restrict the cookie bits that must match when the command is OFPFC_MODIFY* or OFPFC_DELETE* |
table_id | ID of the table to put the flow in |
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_RESET_COUNTS OFPFF_NO_PKT_COUNTS OFPFF_NO_BYT_COUNTS |
|
instructions | An array of OFPInstruction*
|
For more details, see section of A.3.4.1 of the OpenFlow spec.
Example:
def send_flow_mod(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
match = ofp_parser.OFPMatch()
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_NORMAL, 0)]
inst = [ofp_parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
actions)]
req = ofp_parser.OFPFlowMod(datapath=datapath,
cookie=0, cookie_mask=0,
table_id=0, command=ofp.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=32768,
buffer_id=0xffffffff,
out_port=ofp.OFPP_ANY,
out_group=ofp.OFPG_ANY,
flags=ofp.OFPFF_SEND_FLOW_REM,
match=match, instructions=inst)
datapath.send_msg(req)
The controller sends OFPGroupMod to modify the group table.
OFPGroupMod
class OFPGroupMod(MsgBase):
def __init__(self, datapath, command, type_, group_id, buckets):
super(OFPGroupMod, self).__init__(datapath)
self.command = command
self.type = type_
self.group_id = group_id
self.buckets = buckets
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
command | One of the following values |
OFPFC_ADD OFPFC_MODIFY OFPFC_DELETE |
|
type_ | One of the following values |
OFPGT_ALL OFPGT_SELECT OFPGT_INDIRECT OFPGT_FF |
|
group_id | Group identifier |
buckets | An array of OFPBucket
|
For more details, see section of A.3.4.2 of the OpenFlow spec.
Example:
def send_group_mod(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_NORMAL, 0)]
buckets = [ofp_parser.OFPBucket(len_=0, weight=0, watch_port=0,
watch_group=0, actions=actions)]
req = ofp_parser.OFPGroupMod(datapath=datapath,
command=ofp.OFPFC_ADD,
type_=ofp.OFPGT_ALL,
group_id=0,
buckets=buckets)
datapath.send_msg(req)
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_RECV 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_40GB_FD OFPPF_100GB_FD OFPPF_1TB_FD OFPPF_OTHER OFPPF_COPPER OFPPF_FIBER OFPPF_AUTONEG OFPPF_PAUSE OFPPF_PAUSE_ASYM |
For more details, see section of A.3.4.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=0,
mask=(ofp.OFPPC_PORT_DOWN | ofp.OFPPC_NO_RECV |
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)
The controller uses OFPDescStatsRequest to query description of the OpenFlow switch.
OFPDescStatsRequest
class OFPPortDescStatsRequest(OFPMultipartRequest):
def __init__(self, datapath, flags):
super(OFPPortDescStatsRequest, self).__init__(datapath, flags)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Zero or OFPMPF_REQ_MORE
|
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPDescStats
|
For more details, see section of A.3.5.1 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.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_DESC:
self.show_desc_stats(msg.body)
def show_desc_stats(self, body):
self.logger.debug('DescStats: 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))
The controller uses OFPFlowStatsRequest to query individual flow statistics.
OFPFlowStatsRequest
class OFPFlowStatsRequest(OFPFlowStatsRequestBase):
def __init__(self, datapath, flags, table_id, out_port, out_group,
cookie, cookie_mask, match):
super(OFPFlowStatsRequest, self).__init__(datapath, flags, table_id,
out_port, out_group,
cookie, cookie_mask, match)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Zero or OFPMPF_REQ_MORE
|
table_id | ID of table to read |
out_port | Require matching entries to include this as an output port |
out_group | Require matching entries to include this as an output group |
cookie | Require matching entries to contain this cookie value |
cookie_mask | Mask used to restrict the cookie bits that must match |
match | Instance of OFPMatch
|
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPFlowStats
|
For more details, see section of A.3.5.2 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, table_id=ofp.OFPTT_ALL,
out_port=ofp.OFPP_ANY, out_group=ofp.OFPG_ANY,
cookie=0, cookie_mask=0,
match=ofp_parser.OFPMatch())
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_FLOW:
self.show_flow_stats(msg.body)
def show_flow_stats(self, body):
flows = []
for stat in body:
flows.append('length=%d table_id=%s '
'duration_sec=%d duration_nsec=%d '
'priority=%d '
'idle_timeout=%d hard_timeout=%d flags=0x%04x '
'cookie=%d packet_count=%d byte_count=%d '
'match=%s' %
(stat.length, stat.table_id,
stat.duration_sec, stat.duration_nsec,
stat.priority,
stat.idle_timeout, stat.hard_timeout, stat.flags,
stat.cookie, stat.packet_count, stat.byte_count,
stat.match))
self.logger.debug('FlowStats: %s', flows)
The controller uses OFPFlowStatsRequest to query aggregate flow statistics.
OFPAggregateStatsRequest
class OFPAggregateStatsRequest(OFPFlowStatsRequestBase):
def __init__(self, datapath, flags, table_id, out_port, out_group,
cookie, cookie_mask, match):
super(OFPAggregateStatsRequest, self).__init__(datapath,
table_id,
out_port,
out_group,
cookie,
cookie_mask,
match)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Zero or OFPMPF_REQ_MORE
|
table_id | ID of table to read |
out_port | Require matching entries to include this as an output port |
out_group | Require matching entries to include this as an output group |
cookie | Require matching entries to contain this cookie value |
cookie_mask | Mask used to restrict the cookie bits that must match |
match | Instance of OFPMatch
|
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPAggregateStats
|
For more details, see section of A.3.5.3 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, table_id=ofp.OFPTT_ALL,
out_port=ofp.OFPP_ANY, out_group=ofp.OFPG_ANY,
cookie=0, cookie_mask=0,
match=ofp_parser.OFPMatch())
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_AGGREGATE:
self.show_aggregate_stats(msg.body)
def show_aggregate_stats(self, body):
aggregates = []
for stat in body:
aggregates.append('packet_count=%d byte_count=%d flow_count=%d' %
(stat.packet_count, stat.byte_count,
stat.flow_count))
self.logger.debug('AggregateStats: %s', aggregates)
The controller uses OFPTableStatsRequest to query flow table statistics.
OFPTableStatsRequest
class OFPTableStatsRequest(OFPMultipartRequest):
def __init__(self, datapath, flags):
super(OFPTableStatsRequest, self).__init__(datapath, flags)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Zero or OFPMPF_REQ_MORE
|
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPTableStats
|
For more details, see section of A.3.5.4 of the OpenFlow spec.
Example:
def send_table_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPTableStatsRequest(datapath, 0)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_TABLE:
self.show_table_stats(msg.body)
def show_table_stats(self, body):
tables = []
for stat in body:
tables.append('table_id=%d active_count=%d lookup_count=%d '
' matched_count=%d' %
(stat.table_id, stat.active_count, stat.lookup_count,
stat.matched_count))
self.logger.debug('TableStats: %s', tables)
The controller uses OFPPortStatsRequest to query information about physical port.
OFPPortStatsRequest
class OFPPortStatsRequest(OFPMultipartRequest):
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 | Zero or OFPMPF_REQ_MORE
|
port_no | Port number to read |
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPPortStats
|
For more details, see section of A.3.5.6 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_ANY)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_PORT_STATS:
self.show_port_stats(msg.body)
def show_port_stats(self, body):
ports = []
for stat in body:
ports.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 duration_sec=%d duration_nsec=%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,
stat.duration_sec, stat.duration_nsec))
self.logger.debug('PortStats: %s', ports)
The controller uses OFPQueueStatsRequest to query description of all the ports.
OFPPortDescStatsRequest
class OFPPortDescStatsReply(OFPMultipartReply):
def __init__(self, datapath):
super(OFPPortDescStatsReply, self).__init__(datapath)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Zero or OFPMPF_REQ_MORE
|
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPPortDescStats
|
For more details, see section of A.3.5.7 of the OpenFlow spec.
Example:
def send_port_desc_stats_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPPortDescStatsRequest(datapath, 0)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_PORT_DESC:
self.show_port_desc(msg.body, dp)
def show_port_desc(self, body, datapath):
ports = []
for p in body:
ports.append('port_no=%d hw_addr=%s name=%s config=0x%08x '
'state=0x%08x curr=0x%08x advertised=0x%08x '
'supported=0x%08x curr_speed=%d max_speed=%d' %
(p.port_no, mac.haddr_to_str(p.hw_addr),
p.name.rstrip('\0'), p.config,
p.state, p.curr, p.advertised,
p.supported, p.curr_speed, p.max_speed))
self.logger.debug('OFPPortDescStatsReply received: %s', ports)
The controller uses OFPQueueStatsRequest to query statistics of one or more ports.
OFPQueueStatsRequest
class OFPQueueStatsRequest(OFPMultipartRequest):
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 | Zero or OFPMPF_REQ_MORE
|
port_no | Port number to read |
queue_id | ID of queue to read |
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPQueueStats
|
For more details, see section of A.3.5.8 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, 0, ofp.OFPP_ANY,
ofp.OFPQ_ALL)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_QUEUE:
self.show_queue_stats(msg.body)
def show_queue_stats(self, body):
queues = []
for stat in body:
queues.append('port_no=%d queue_id=%d '
'tx_bytes=%d tx_packets=%d tx_errors=%d '
'duration_sec=%d duration_nsec=%d' %
(stat.port_no, stat.queue_id,
stat.tx_bytes, stat.tx_packets, stat.tx_errors,
stat.duration_sec, stat.duration_nsec))
self.logger.debug('QueueStats: %s', queues)
The controller uses OFPGroupStatsRequest to query statistics of one or more groups.
OFPGroupStatsRequest
class OFPGroupStatsRequest(OFPMultipartRequest):
def __init__(self, datapath, flags, group_id):
super(OFPGroupStatsRequest, self).__init__(datapath, flags)
self.group_id = group_id
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Zero or OFPMPF_REQ_MORE
|
group_id | ID of group to read. All groups if OFPG_ALL
|
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPGroupStats
|
For more details, see section of A.3.5.9 of the OpenFlow spec.
Example:
def send_group_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPGroupStatsRequest(datapath, 0, ofp.OFPG_ALL)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_GROUP:
self.show_group_stats(msg.body)
def show_group_stats(self, body):
groups = []
for stat in body:
groups.append('length=%d group_id=%d '
'ref_count=%d packet_count=%d byte_count=%d '
'duration_sec=%d duration_nsec=%d' %
(stat.length, stat.group_id,
stat.ref_count, stat.packet_count, stat.byte_count,
stat.duration_sec, stat.duration_nsec))
self.logger.debug('GroupStats: %s', groups)
The controller uses OFPGroupStatsRequest to list the set of groups on a switch.
OFPGroupDescStatsRequest
class OFPGroupDescStatsRequest(OFPMultipartRequest):
def __init__(self, datapath, flags, port_no):
super(OFPGroupDescStatsRequest, self).__init__(datapath, flags)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Zero or OFPMPF_REQ_MORE
|
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPGroupDescStats
|
For more details, see section of A.3.5.10 of the OpenFlow spec.
Example:
def send_group_desc_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPGroupDescStatsRequest(datapath, 0)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_GROUP_DESC:
self.show_group_desc_stats(msg.body)
def show_group_desc_stats(self, body):
descs = []
for stat in body:
descs.append('length=%d type=%d group_id=%d '
'buckets=%s' %
(stat.length, stat.type, stat.group_id,
stat.bucket))
self.logger.debug('GroupDescStats: %s', groups)
The controller uses OFPGroupFeaturesStatsRequest to list the capabilities of groups on a switch.
OFPGroupFeaturesStatsRequest
class OFPGroupFeaturesStatsRequest(OFPMultipartRequest):
def __init__(self, datapath, flags, port_no):
super(OFPGroupFeaturesRequest, self).__init__(datapath, flags)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Zero or OFPMPF_REQ_MORE
|
OFPGroupFeaturesStatsReply
attribute | description |
---|---|
body | Instance of OFPGroupFeaturesStats
|
For more details, see section of A.3.5.11 of the OpenFlow spec.
Example:
def send_group_features_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPGroupFeaturesStatsRequest(datapath, 0)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_GROUP_FEATURES:
self.show_group_features_stats(msg.body)
def show_group_features_stats(self, body):
features = []
for stat in body:
features.append('types=%d capabilities=0x%08x max_groups=%s '
'actions=%s' %
(stat.types, stat.capabilities, stat.max_groups,
stat.actions))
self.logger.debug('GroupFeaturesStats: %s', features)
The controller uses OFPMeterStatsRequest to query statistics for one or more meters.
OFPMeterStatsRequest
class OFPMeterStatsRequest(OFPMultipartRequest):
def __init__(self, datapath, flags, meter_id):
super(OFPMeterStatsRequest, self).__init__(datapath, flags)
self.meter_id = meter_id
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Zero or OFPMPF_REQ_MORE
|
meter_id | ID of meter to read, or OFPM_ALL
|
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPMeterStats
|
For more details, see section of A.3.5.12 of the OpenFlow spec.
Example:
def send_meter_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPMeterStatsRequest(datapath, 0, ofp.OFPM_ALL)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_METER:
self.show_meter_stats(msg.body, dp)
def show_meter_stats(self, body):
meters = []
for stat in body:
meters.append('meter_id=0x%08x len=%d flow_count=%d '
'packet_in_count=%d byte_in_count=%d '
'duration_sec=%d duration_nsec=%d '
'band_stats=%s' %
(stat.meter_id, stat.len, stat.flow_count,
stat.packet_in_count, stat.byte_in_count,
stat.duration_sec, stat.duration_nsec,
stat.band_stats))
self.logger.debug('MeterStats: %s', meters)
The controller uses OFPMeterConfigStatsRequest to query configuration for one or more meters.
OFPMeterConfigStatsRequest
class OFPMeterConfigStatsRequest(OFPMultipartRequest):
def __init__(self, datapath, flags, meter_id):
super(OFPMeterConfigStatsRequest, self).__init__(datapath, flags)
self.meter_id = meter_id
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Zero or OFPMPF_REQ_MORE
|
meter_id | ID of meter to read, or OFPM_ALL
|
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPMeterConfigStats
|
For more details, see section of A.3.5.13 of the OpenFlow spec.
Example:
def send_meter_config_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPMeterConfigStatsRequest(datapath, 0, ofp.OFPM_ALL)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_METER_CONFIG:
self.show_meter_config_stats(msg.body, dp)
def show_meter_config_stats(self, body):
configs = []
for stat in body:
configs.append('length=%d flags=0x%04x meter_id=0x%08x '
'bands=%s' %
(stat.length, stat.flags, stat.meter_id,
stat.bands))
self.logger.debug('MeterConfigStats: %s', configs)
The controller uses OFPMeterFeaturesStatsRequest to query the set of features of the metering subsystem.
OFPMeterFeaturesStatsRequest
class OFPMeterFeaturesStatsRequest(OFPMultipartRequest):
def __init__(self, datapath, flags):
super(OFPMeterFeaturesStatsRequest, self).__init__(datapath, flags)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
flags | Zero or OFPMPF_REQ_MORE
|
OFPMultipartReply
attribute | description |
---|---|
body | Instance of OFPMeterFeaturesStats
|
For more details, see section of A.3.5.14 of the OpenFlow spec.
Example:
def send_meter_features_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPMeterFeaturesStatsRequest(datapath, 0)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPMultipartReply, MAIN_DISPATCHER)
def multipart_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
self.logger.debug('OFPMultipartReply received:')
if msg.type == ofp.OFPMP_METER_FEATURES:
self.show_meter_features_stats(msg.body, dp)
def show_meter_features_stats(self, body):
features = []
for stat in body:
features.append('max_meter=%d band_types=0x%08x '
'capabilities=0x%08x max_band=%d max_color=%d' %
(stat.max_meter, stat.band_types,
stat.capabilities, stat.max_band, stat.max_color))
self.logger.debug('MeterFeaturesStats: %s', configs)
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 A.3.6 of the OpenFlow spec.
Example:
def send_queue_get_config_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPQueueGetConfigRequest(datapath, ofp.OFPP_ANY)
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)
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):
assert in_port is not None
super(OFPPacketOut, self).__init__(datapath)
self.buffer_id = buffer_id
self.in_port = in_port
self.actions_len = 0
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_CONTROLLER
|
actions | An array of OpenFlow action class |
data | Packet data |
For more details, see section of A.3.7 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
in_port = 0
for f in msg.match.fields:
if isinstance(f, ofp_parser.MTInPort):
in_port = f.value
self.send_packet_out(dp, msg.buffer_id, in_port)
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, 0)]
req = ofp_parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id,
in_port=in_port, actions=actions)
datapath.send_msg(req)
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.
For more details, see section of A.3.8 of the OpenFlow spec.
Example:
def send_barrier_request(self, datapath):
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')
The controller sends OFPRoleRequest to change its role.
OFPRoleRequest
class OFPRoleRequest(MsgBase):
def __init__(self, datapath, role, generation_id):
super(OFPRoleRequest, self).__init__(datapath)
self.role = role
self.generation_id = generation_id
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
role | One of the following values |
OFPCR_ROLE_NOCHANGE OFPCR_ROLE_EQUAL OFPCR_ROLE_MASTER OFPCR_ROLE_SLAVE |
|
generation_id | Master Election Generation ID |
OFPRoleReply
This class has no special attribute.
For more details, see section of A.3.9 of the OpenFlow spec.
Example:
def send_role_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPRoleRequest(datapath, ofp.OFPCR_ROLE_EQUAL, 0)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPRoleReply, MAIN_DISPATCHER)
def role_reply_handler(self, ev):
self.logger.debug('OFPRoleReply received')
The controller sends OFPSetAsync to set the asynchronous messages that it wants to receive on a given OpenFlow channel, sends OFPGetAsyncRequest to query the asynchronous configuration.
OFPSetAsync
class OFPSetAsync(MsgBase):
def __init__(self, datapath,
packet_in_mask, port_status_mask, flow_removed_mask):
super(OFPSetAsync, self).__init__(datapath)
self.packet_in_mask = packet_in_mask
self.port_status_mask = port_status_mask
self.flow_removed_mask = flow_removed_mask
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
packet_in_mask |
2-element array: element 0, when the controller has a OFPCR_ROLE_EQUAL or
OFPCR_ROLE_MASTER role. element 1, when the controller has a OFPCR_ROLE_SLAVE
role. Bitmap of the following flags |
OFPR_NO_MATCH OFPR_ACTION OFPR_INVALID_TTL |
|
port_status_mask |
2-element array. Bitmap of the following flags |
OFPPR_ADD OFPPR_DELETE OFPPR_MODIFY |
|
flow_removed_mask |
2-element array. Bitmap of the following flags |
OFPRR_IDLE_TIMEOUT OFPRR_HARD_TIMEOUT OFPRR_DELETE OFPRR_GROUP_DELETE |
OFPGetAsyncRequest
class OFPGetAsyncRequest(MsgBase):
def __init__(self, datapath):
super(OFPGetAsyncRequest, self).__init__(datapath)
parameter | description |
---|---|
datapath | Instance of ryu.controller.controller.Datapath
|
*OFPGetAsyncReply:
attribute | description |
---|---|
packet_in_mask | Bitmasks of following values |
OFPR_NO_MATCH OFPR_ACTION OFPR_INVALID_TTL |
|
port_status_mask | Bitmasks of following values |
OFPPR_ADD OFPPR_DELETE OFPPR_MODIFY |
|
flow_removed_mask | Bitmasks of following values |
OFPRR_IDLE_TIMEOUT OFPRR_HARD_TIMEOUT OFPRR_DELETE OFPRR_GROUP_DELETE |
For more details, see section of A.3.10 of the OpenFlow spec.
Example:
def send_set_async(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPSetAsync(
datapath=datapath,
packet_in_mask=[ofp.OFPR_ACTION|ofp.OFPR_INVALID_TTL, 0],
port_status_mask=[
ofp.OFPPR_ADD|ofp.OFPPR_DELETE|ofp.OFPPR_MODIFY, 0],
flow_removed_mask=[
ofp.OFPRR_IDLE_TIMEOUT|ofp.OFPRR_HARD_TIMEOUT|ofp.OFPRR_DELETE,
0])
datapath.send_msg(req)
def send_get_async_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPGetAsyncRequest(datapath)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPGetAsyncReply, MAIN_DISPATCHER)
def get_async_reply_handler(self, ev):
msg = ev.msg
self.logger.debug('OFPGetAsyncReply received: '
'packet_in_mask=[0x%08x, 0x%08x] '
'port_status_mask=[0x%08x, 0x%08x] '
'flow_removed_mask=[0x%08x, 0x%08x]',
msg.packet_in_mask[0], msg.packet_in_mask[1],
msg.port_status_mask[0], msg.port_status_mask[1],
msg.flow_removed_mask[0], msg.flow_removed_mask[1])
These messages are sent from the switch, and Ryu application can handle these as an event.
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 |
reason | Reason packet is being sent |
OFPR_NO_MATCH OFPR_ACTION OFPR_INVALID_TTL |
|
table_id | ID of the table that was looked up |
match | Instance of OFPMatch
|
data | Ethernet frame |
For more details, see section of A.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
ofp_parser = dp.ofproto_parser
if msg.reason == ofp.OFPR_NO_MATCH:
reason = 'NO MATCH'
elif msg.reason == ofp.OFPR_ACTION:
reason = 'ACTION'
elif msg.reason == ofp.OFPR_INVALID_TTL:
reason = 'INVALID TTL'
else:
reason = 'unknown'
field = []
for f in msg.match.fields:
field.append('%s: value=%s' % (f.__class__.__name__, f.value))
self.logger.debug('OFPPacketIn received: '
'buffer_id=%x total_len=%d reason=%s table_id=%d '
'cookie=%d match.fields=%s data=%s',
msg.buffer_id, msg.total_len, reason, msg.table_id,
msg.cookie, field, utils.hex_array(msg.data))
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 OFPRR_GROUP_DELETE |
|
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 |
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 A.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'
elif msg.reason == ofp.OFPRR_GROUP_DELETE:
reason = 'GROUP DELETE'
else:
reason = 'unknown'
field = []
for f in msg.match.fields:
field.append('%s: value=%s' % (f.__class__.__name__, f.value))
self.logger.debug('OFPFlowRemoved received: '
'cookie=%d priority=%d reason=%s table_id=%d '
'duration_sec=%d duration_nsec=%d '
'idle_timeout=%d hard_timeout=%d '
'packet_count=%d byte_count=%d match.fields=%s',
msg.cookie, msg.priority, reason, msg.table_id,
msg.duration_sec, msg.duration_nsec,
msg.idle_timeout, msg.hard_timeout,
msg.packet_count, msg.byte_count, field)
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 OFPPort
|
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:
reason = 'ADD'
elif msg.reason == ofp.OFPPR_DELETE:
reason = 'DELETE'
elif msg.reason == ofp.OFPPR_MODIFY:
reason = 'MODIFY'
else:
reason = 'unknown'
self.logger.debug('OFPPortStatus received: reason=%s desc=%s',
reason, msg.desc)
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_3
.
Type | Code |
---|---|
OFPET_HELLO_FAILED |
OFPHFC_INCOMPATIBLE OFPHFC_EPERM |
OFPET_BAD_REQUEST |
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 |
OFPET_BAD_ACTION |
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 |
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 |
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 |
OFPFMFC_UNKNOWN OFPFMFC_TABLE_FULL OFPFMFC_BAD_TABLE_ID OFPFMFC_OVERLAP OFPFMFC_EPERM OFPFMFC_BAD_TIMEOUT OFPFMFC_BAD_COMMAND OFPFMFC_BAD_FLAGS |
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 |
OFPPMFC_BAD_PORT OFPPMFC_BAD_HW_ADDR OFPPMFC_BAD_CONFIG OFPPMFC_BAD_ADVERTISE OFPPMFC_EPERM |
OFPET_TABLE_MOD_FAILED |
OFPTMFC_BAD_TABLE OFPTMFC_BAD_CONFIG OFPTMFC_EPERM |
OFPET_QUEUE_OP_FAILED |
OFPQOFC_BAD_PORT OFPQOFC_BAD_QUEUE OFPQOFC_EPERM |
OFPET_SWITCH_CONFIG_FAILED |
OFPSCFC_BAD_FLAGS OFPSCFC_BAD_LEN OFPQCFC_EPERM |
OFPET_ROLE_REQUEST_FAILED |
OFPRRFC_STALE OFPRRFC_UNSUP OFPRRFC_BAD_ROLE |
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 |
OFPET_TABLE_FEATURES_FAILED |
OFPTFFC_BAD_TABLE OFPTFFC_BAD_METADATA OFPTFFC_BAD_TYPE OFPTFFC_BAD_LEN OFPTFFC_BAD_ARGUMENT OFPTFFC_EPERM |
OFPET_EXPERIMENTER | N/A |
For more details, see section of A.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 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.
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.
For more details, see section of A.5.1 of the OpenFlow spec.
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)
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 |
For more details, see section of A.5.2 of the OpenFlow spec.
Example:
@set_ev_cls(ofp_event.EventOFPEchoRequest,
[HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
def echo_request_handler(self, ev):
msg = ev.msg
dp = msg.datapath
self.logger.debug('OFPEchoRequest received: data=%s',
utils.hex_array(msg.data))
self.send_echo_reply(dp, msg.data)
def send_echo_request(self, datapath, data):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPEchoRequest(datapath)
req.data = data
datapath.send_msg(req)
When OFPEchoRequest is received, you must return OFPEchoReply.
OFPEchoReply
attribute | description |
---|---|
data | The unmodified data of an echo request message |
For more details, see section of A.5.3 of the OpenFlow spec.
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))
def send_echo_reply(self, datapath, data):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
reply = ofp_parser.OFPEchoReply(datapath)
reply.data = data
datapath.send_msg(reply)
This is an experimenter extension message.
OFPExperimenter
Attribute | Description |
---|---|
experimenter | Experimenter ID |
exp_type | Experimenter defined |
For more details, see section of A.5.4 of the OpenFlow spec.
OpenFlow Match structure is defined in
ryu.ofproto.ofproto_v1_3_parser.OFPMatch
.
class OFPMatch(object):
def __init__(self):
super(OFPMatch, self).__init__()
self.wc = FlowWildcards()
self.flow = Flow()
self.fields = []
Method | Description |
---|---|
set_in_port(self, port) | Switch input port |
set_in_phy_port(self, phy_port) | Switch physical input port |
set_metadata(self, metadata) | Metadata passed between tables |
set_metadata_masked(self, metadata, mask) | Metadata and its mask |
set_dl_dst(self, dl_dst) | Ethernet destination address |
set_dl_dst_masked(self, dl_dst, mask) | Ethernet destination address and its mask |
set_dl_src(self, dl_src) | Ethernet source address |
set_dl_src_masked(self, dl_src, mask) | Ethernet source address and its mask |
set_dl_type(self, dl_type) | Ethernet frame type |
set_vlan_vid(self, vid) | VLAN ID |
set_vlan_vid_masked(self, vid, mask) | VLAN ID and its mask |
set_vlan_pcp(self, pcp) | VLAN priority |
set_ip_dscp(self, ip_dscp) | IP DSCP (6 bits in ToS field) |
set_ip_ecn(self, ip_ecn) | IP ECN (2 bits in ToS field) |
set_ip_proto(self, ip_proto) | IP protocol |
set_ipv4_src(self, ipv4_src) | IPv4 source address |
set_ipv4_src_masked(self, ipv4_src, mask) | IPv4 source address and its mask |
set_ipv4_dst(self, ipv4_dst) | IPv4 destination address |
set_ipv4_dst_masked(self, ipv4_dst, mask) | IPv4 destination address and its mask |
set_tcp_src(self, tcp_src) | TCP source port |
set_tcp_dst(self, tcp_dst) | TCP destination port |
set_udp_src(self, udp_src) | UDP source port |
set_udp_dst(self, udp_dst) | UDP destination port |
set_sctp_src(self, sctp_src) | SCTP source port |
set_sctp_dst(self, sctp_dst) | SCTP destination port |
set_icmpv4_type(self, icmpv4_type) | ICMP type |
set_icmpv4_code(self, icmpv4_code) | ICMP code |
set_arp_opcode(self, arp_op) | ARP opcode |
set_arp_spa(self, arp_spa) | ARP source IPv4 address |
set_arp_spa_masked(self, arp_spa, mask) | ARP source IPv4 address and its mask |
set_arp_tpa(self, arp_tpa) | ARP target IPv4 address |
set_arp_tpa_masked(self, arp_tpa, mask): | ARP target IPv4 address and its mask |
set_arp_sha(self, arp_sha) | ARP source hardware address |
set_arp_sha_masked(self, arp_sha, mask) | ARP source hardware address and its mask |
set_arp_tha(self, arp_tha) | ARP target hardware address |
set_arp_tha_masked(self, arp_tha, mask) | ARP target hardware address and its mask |
set_ipv6_src(self, src) | IPv6 source address |
set_ipv6_src_masked(self, src, mask) | IPv6 source address and its mask |
set_ipv6_dst(self, dst) | IPv6 destination address |
set_ipv6_dst_masked(self, dst, mask) | IPv6 destination address and its mask |
set_ipv6_flabel(self, flabel) | IPv6 Flow Label |
set_ipv6_flabel_masked(self, flabel, mask) | IPv6 Flow Label and its mask |
set_icmpv6_type(self, icmpv6_type) | ICMPv6 type |
set_icmpv6_code(self, icmpv6_code) | ICMPv6 code |
set_ipv6_nd_target(self, target) | Target address for ND |
set_ipv6_nd_sll(self, ipv6_nd_sll) | Source link-layer for ND |
set_ipv6_nd_tll(self, ipv6_nd_tll) | Target link-layer for ND |
set_mpls_label(self, mpls_label) | MPLS label |
set_mpls_tc(self, mpls_tc) | MPLS TC |
set_mpls_bos(self, bos) | MPLS BoS bit |
set_pbb_isid(self, isid) | PBB I-SID |
set_pbb_isid_masked(self, isid, mask) | PBB I-SID and its mask |
set_tunnel_id(self, tunnel_id) | Logical Port Metadata |
set_tunnel_id_masked(self, tunnel_id, mask) | Logical Port Metadata and its mask |
set_ipv6_exthdr(self, hdr) | IPv6 Extension Header pseudo-field |
set_ipv6_exthdr_masked(self, hdr, mask) | IPv6 Extension Header pseudo-field and its mask |
For more details, see section of A.2.3 of the OpenFlow spec.
Example:
# Ethernet broadcat frame
match = ofp_parser.OFPMatch()
match.set_dl_dst(ryu.lib.mac.haddr_to_bin('ff:ff:ff:ff:ff:ff'))
# From port1 and source MAC address is '00:00:00:00:00:01'
match = ofp_parser.OFPMatch()
match.set_in_port(1)
match.set_dl_src(ryu.lib.mac.haddr_to_bin('00:00:00:00:00:01'))
OpenFlow Instructions and Actions are defined in
ryu.ofproto.ofproto_v1_3_parser
.
This instruction indicates the next table in the processing pipeline.
class OFPInstructionGotoTable(object):
def __init__(self, table_id):
super(OFPInstructionGotoTable, self).__init__()
self.type = ofproto_v1_3.OFPIT_GOTO_TABLE
self.len = ofproto_v1_3.OFP_INSTRUCTION_GOTO_TABLE_SIZE
self.table_id = table_id
parameter | description |
---|---|
table_id | Next table |
This instruction writes the masked metadata value into the metadata field.
class OFPInstructionWriteMetadata(object):
def __init__(self, metadata, metadata_mask):
super(OFPInstructionWriteMetadata, self).__init__()
self.type = ofproto_v1_3.OFPIT_WRITE_METADATA
self.len = ofproto_v1_3.OFP_INSTRUCTION_WRITE_METADATA_SIZE
self.metadata = metadata
self.metadata_mask = metadata_mask
parameter | description |
---|---|
metadata | Metadata value to write |
metadata_mask | Metadata write bitmask |
This instruction writes/applies/clears the actions.
class OFPInstructionActions(object):
def __init__(self, type_, actions=None):
super(OFPInstructionActions, self).__init__()
self.type = type_
self.actions = actions
parameter | description |
---|---|
type_ | One of following values |
OFPIT_WRITE_ACTIONS OFPIT_APPLY_ACTIONS OFPIT_CLEAR_ACTIONS |
|
actions | An array of OpenFlow action class |
This action indicates output a packet to the switch port.
class OFPActionOutput(OFPAction):
def __init__(self, port, max_len):
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 the group used to process this packet.
class OFPActionGroup(OFPAction):
def __init__(self, group_id):
super(OFPActionGroup, self).__init__()
self.group_id = group_id
parameter | description |
---|---|
group_id | Group identifier |
This action sets the queue id that will be used to map a flow to an already-configured queueu on a port.
class OFPActionSetQueue(OFPAction):
def __init__(self, queue_id):
super(OFPActionSetQueue, self).__init__()
self.queue_id = queue_id
parameter | description |
---|---|
queue_id | Queue id for the packets |
This action sets the MPLS TTL.
class OFPActionSetMplsTtl(OFPAction):
def __init__(self, mpls_ttl):
super(OFPActionSetMplsTtl, self).__init__()
self.mpls_ttl = mpls_ttl
parameter | description |
---|---|
mpls_ttl | MPLS TTL |
This action decrements the MPLS TTL.
class OFPActionDecMplsTtl(OFPAction):
def __init__(self):
super(OFPActionDecMplsTtl, self).__init__()
This action sets the IP TTL.
class OFPActionSetNwTtl(OFPAction):
def __init__(self, nw_ttl):
super(OFPActionSetNwTtl, self).__init__()
self.nw_ttl = nw_ttl
parameter | description |
---|---|
nw_ttl | IP TTL |
This action decrements the IP TTL.
class OFPActionDecNwTtl(OFPAction):
def __init__(self):
super(OFPActionDecNwTtl, self).__init__()
This action copies the TTL from the next-to-outermost header with TTL to the outermost header with TTL.
class OFPActionCopyTtlOut(OFPAction):
def __init__(self):
super(OFPActionCopyTtlOut, self).__init__()
This action copies the TTL from the outermost header with TTL to the next-to-outermost header with TTL.
class OFPActionCopyTtlIn(OFPAction):
def __init__(self):
super(OFPActionCopyTtlIn, self).__init__()
This action pushes a new VLAN tag to the packet.
class OFPActionPushVlan(OFPAction):
def __init__(self, ethertype):
super(OFPActionPushVlan, self).__init__()
self.ethertype = ethertype
parameter | description |
---|---|
ethertype | Ethertype |
This action pushes a new MPLS header to the packet.
class OFPActionPushMpls(OFPAction):
def __init__(self, ethertype):
super(OFPActionPushMpls, self).__init__()
self.ethertype = ethertype
parameter | description |
---|---|
ethertype | Ethertype |
This action pops the outermost VLAN tag from the packet.
class OFPActionPopVlan(OFPAction):
def __init__(self):
super(OFPActionPopVlan, self).__init__()
This action pops the MPLS header from the packet.
class OFPActionPopMpls(OFPAction):
def __init__(self, ethertype):
super(OFPActionPopMpls, self).__init__()
self.ethertype = ethertype
parameter | description |
---|---|
ethertype | Ethertype of the payload |
This action modifies a header field in the packet.
class OFPActionSetField(OFPAction):
def __init__(self, field):
super(OFPActionSetField, self).__init__()
self.field = field
parameter | description |
---|---|
field | Instance of OFPMatchField
|
This action is an extensible action for the experimenter.
class OFPActionExperimenter(OFPAction):
def __init__(self, experimenter):
super(OFPActionExperimenter, self).__init__()
self.experimenter = experimenter
parameter | description |
---|---|
experimenter | Experimenter ID |