From 7ef69e02596b4884acecacaf91ead153a67ee7ed Mon Sep 17 00:00:00 2001 From: Yiannis Yiakoumis Date: Thu, 3 Dec 2009 13:22:20 -0800 Subject: [PATCH] Introduce slicing mechanism changes in spec and openflow.h For further details refer to this feature wiki-page: http://openflowswitch.org/wk/index.php/Slicing --- doc/of-spec/appendix.tex | 68 ++++++++++++++- doc/of-spec/openflow-spec-v0.9.0.tex | 15 +++- include/openflow/openflow.h | 121 +++++++++++++++++++++++++-- 3 files changed, 194 insertions(+), 10 deletions(-) diff --git a/doc/of-spec/appendix.tex b/doc/of-spec/appendix.tex index 817de23..a6b5108 100755 --- a/doc/of-spec/appendix.tex +++ b/doc/of-spec/appendix.tex @@ -45,6 +45,25 @@ The \verb|curr|, \verb|advertised|, \verb|supported|, and \verb|peer| fields ind \input{enum/ofp_port_features} Multiple of these flags may be set simultaneously. +\subsubsection{\qosupd{Queue Structures}} +\label{cts:qos} +\qosupd{An OpenFlow switch provides limited Quality-of-Service support + (QoS) through a simple queuing +mechanism. One (or more) queues can attach to a port and be used to map flows +on it. Flows mapped to a specific queue will be treated according to +that queue's configuration (e.g. min rate). +\\\\ +A queue is described by the} \verb|ofp_packet_queue| \qosupd{structure: +\input{struct/ofp_packet_queue} +Each queue is further described by a set of properties, each of a +specific type and configuration. +\input{enum/ofp_queue_properties} +Each queue property description starts with a common header: +\input{struct/ofp_queue_prop_header} +Currently, there is only a minimum-rate type queue, described by the} +\verb|ofp_queue_prop_min_rate| \qosupd{structure: +\input{struct/ofp_queue_prop_min_rate}} + \subsubsection{Flow Match Structures} When describing a flow entry, the following structure is used: @@ -60,7 +79,7 @@ The source and destination netmasks are each specified with a 6-bit number in th A number of actions may be associated with flows or packets. The currently defined action types are: \input{enum/ofp_action_type} -Output actions are described in Section \ref{ft:actions}, while Field-Modify actions are described in Table \ref{table:field modify actions}. An action definition contains the action type, length, and any associated data: +Output \qosupd{and enqueue} actions are described in Section \ref{ft:actions}, while Field-Modify actions are described in Table \ref{table:field modify actions}. An action definition contains the action type, length, and any associated data: \input{struct/ofp_action_header} An \verb|action_output| has the following fields: @@ -68,6 +87,20 @@ An \verb|action_output| has the following fields: \input{struct/ofp_action_output} The \verb|max_len| indicates the maximum amount of data from a packet that should be sent when the port is \verb|OFPP_CONTROLLER|. If \verb|max_len| is zero, the switch must send a zero-size \verb|packet_in| message. The \verb|port| specifies the physical port from which packets should be sent. \\\\ +\qosupd{The enqueue action maps a flow to an already-configured queue, regardless of the TOS and VLAN PCP bits. + The packet should not change after an enqueue action. If the switch + needs to set the TOS/PCP bits for internal handling, the original values + should be restored before sending the packet out. +\\\\ +A switch may support only queues that are tight to specific PCP/TOS +bits. In that case, we cannot map an arbitrary flow to a specific +queue, therefore the action ENQUEUE is not supported. The user can +still use these queues and map +flows to them by setting the relevant fields (TOS, VLAN PCP). +\\\\ +The enqueue action has the following fields: + +\input{struct/ofp_action_enqueue}} An \verb|action_vlan_vid| has the following fields: \input{struct/ofp_action_vlan_vid} @@ -173,6 +206,20 @@ The controller uses the \verb|OFPT_PORT_MOD| message to modify the behavior of t \input{struct/ofp_port_mod} The \verb|mask| field is used to select bits in the \verb|config| field to change. The \verb|advertise| field has no mask; all port features change together. +\subsubsection{\qosupd{Queue Configuration Messages}} +\qosupd{Queue configuration takes place outside the OpenFlow protocol, either + through a command line tool or through an external dedicated configuration +protocol. +\\\\ +The controller can query the switch for configured queues on a port +using the following structure: +\input{struct/ofp_queue_get_config_request} +The switch replies back with an} \verb|ofp_queue_get_config_reply| \qosupd{command, containing +a list of configured queues. + +\input{struct/ofp_queue_get_config_reply} +} + \subsubsection{Read State Messages} While the system is running, the datapath may be queried about its current state using the \verb|OFPT_STATS_REQUEST| message: @@ -239,6 +286,20 @@ The body of the reply consists of an array of the following: \input{struct/ofp_port_stats} The switch should return a value of -1 for unavailable counters. +\paragraph{\qosupd{Queue Statistics}} +\qosupd{The} \verb|OFPST_QUEUE| \qosupd{stats request message provides + queue statistics for one or more ports. + The request body consists of a} \verb|port_no| \qosupd{field +identifying the port and a} \verb|queue_id|. \verb|OFPP_ALL| +\qosupd{refers to all ports, while} \verb|OFPQ_ALL| \qosupd{refers to all queues configured +at a port. + +\input{struct/ofp_queue_stats_request} +The body of the reply consists of an array of +the following structure: + +\input{struct/ofp_queue_stats}} + \paragraph{Vendor Statistics} Vendor-specific stats messages are requested with the \verb|OFPST_VENDOR| stats type. The first four bytes of the message are the vendor identifier. The rest of the body is vendor-defined. \\\\ @@ -322,6 +383,11 @@ For the \verb|OFPET_FLOW_MOD_FAILED| error \verb|type|, the following \verb|code \input{enum/ofp_flow_mod_failed_code} The \verb|data| field contains at least 64 bytes of the failed request. \\\\ +For the \verb|OFPET_QUEUE_OP_FAILED| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_queue_op_failed_code} +The \verb|data| field contains at least 64 bytes of the failed request. +\\\\ If the error message is in response to a specific message from the controller, e.g., \verb|OFPET_BAD_REQUEST|, \verb|OFPET_BAD_ACTION|, or \verb|OFPET_FLOW_MOD_FAILED|, then the \verb|xid| field of the header should match that of the offending message. \subsection{Symmetric Messages} diff --git a/doc/of-spec/openflow-spec-v0.9.0.tex b/doc/of-spec/openflow-spec-v0.9.0.tex index 29ab255..7c158e8 100644 --- a/doc/of-spec/openflow-spec-v0.9.0.tex +++ b/doc/of-spec/openflow-spec-v0.9.0.tex @@ -4,6 +4,7 @@ \usepackage{fancyhdr} \usepackage{graphicx} \usepackage{tabularx} +\usepackage{color} \hbadness=10000 % No "underfull hbox" messages @@ -20,6 +21,8 @@ \fontfamily{cmr} % what about cmss? \selectfont +\newcommand{\qosupd}[1]{{\color{blue} #1}} + \title{OpenFlow Switch Specification} \author{Version 0.9.0 ( Wire Protocol \input{define/OFP_VERSION})} \date{\today} @@ -119,7 +122,8 @@ Switch designers are free to implement the internals in any way convenient provi \subsection{Counters} -Counters are maintained per-table, per-flow, and per-port. OpenFlow-compliant counters may be implemented in software and maintained by polling hardware counters with more limited ranges. +Counters are maintained per-table, per-flow, \qosupd{per-port and + per queue}. OpenFlow-compliant counters may be implemented in software and maintained by polling hardware counters with more limited ranges. \\\\ Table \ref{table:counters} contains the required set of counters. Duration refers to the number of seconds a flow has been active. The Receive Errors field includes all explicitly specified errors, including frame, overrun, and CRC errors, plus any others. \begin{table}[!hbp] @@ -149,6 +153,10 @@ Table \ref{table:counters} contains the required set of counters. Duration refe \hline Receive Overrun Errors & 64 \\ \hline Receive CRC Errors & 64 \\ \hline Collisions & 64 \\ +\hline \multicolumn{2}{|c|}{\qosupd{Per Queue}} \\ +\hline \qosupd{Transmit Packets} & \qosupd{64} \\ +\hline \qosupd{Transmit Bytes} & \qosupd{64} \\ +\hline \qosupd{Transmit Overrun Errors} & \qosupd{64}\\ \hline \end{tabular} \caption{Required list of counters for use in statistics messages.} @@ -184,6 +192,11 @@ However, some switches will not be able to support any combination. Therefore, t \\\\ The controller will only ask the switch to send to multiple physical ports simultaneously if the switch indicates it supports this behavior in the initial handshake (see section \ref{cts:handshake}). \\\\ +\textbf{\qosupd{Optional Action:}} \emph{\qosupd{Enqueue}}. \qosupd{The enqueue action forwards +a packet through a queue attached to a port. Forwarding behavior is +dictated by the configuration of the queue and is used to provide +basic Quality-of-Service (QoS) support (see section \ref{cts:qos}).} +\\\\ \textbf{Required Action:} \emph{Drop}. A flow-entry with no specified action indicates that all matching packets should be dropped. \\\\ \textbf{Optional Action:} \emph{Modify-Field}. While not strictly required, the actions shown in Table \ref{table:field modify actions} greatly increase the usefulness of an OpenFlow implementation. To aid integration with existing networks, we suggest that VLAN modification actions be supported. diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 735094d..36cd1fa 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -125,7 +125,12 @@ enum ofp_type { /* Barrier messages. */ OFPT_BARRIER_REQUEST, /* Controller/switch message */ - OFPT_BARRIER_REPLY /* Controller/switch message */ + OFPT_BARRIER_REPLY, /* Controller/switch message */ + + /* Queue Configuration messages. */ + OFPT_QUEUE_GET_CONFIG_REQUEST, /* Controller/switch message */ + OFPT_QUEUE_GET_CONFIG_REPLY /* Controller/switch message */ + }; /* Header on all OpenFlow packets. */ @@ -172,7 +177,8 @@ enum ofp_capabilities { OFPC_STP = 1 << 3, /* 802.1d spanning tree. */ OFPC_MULTI_PHY_TX = 1 << 4, /* Supports transmitting through multiple physical interfaces */ - OFPC_IP_REASM = 1 << 5 /* Can reassemble IP fragments. */ + OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ + OFPC_QUEUE_STATS = 1 << 6 /* Queue statistics */ }; /* Flags to indicate behavior of the physical port. These flags are @@ -285,7 +291,7 @@ OFP_ASSERT(sizeof(struct ofp_port_status) == 64); struct ofp_port_mod { struct ofp_header header; uint16_t port_no; - uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not + uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not configurable. This is used to sanity-check the request, so it must be the same as returned in an @@ -335,6 +341,7 @@ enum ofp_action_type { OFPAT_SET_NW_TOS, /* IP ToS/DSCP field (6 bits). */ OFPAT_SET_TP_SRC, /* TCP/UDP source port. */ OFPAT_SET_TP_DST, /* TCP/UDP destination port. */ + OFPAT_ENQUEUE, /* Output to queue. */ OFPAT_VENDOR = 0xffff }; @@ -416,7 +423,7 @@ struct ofp_action_vendor_header { }; OFP_ASSERT(sizeof(struct ofp_action_vendor_header) == 8); -/* Action header that is common to all actions. The length includes the +/* Action header that is common to all actions. The length includes the * header and any padding used to make the action 64-bit aligned. * NB: The length of an action *must* always be a multiple of eight. */ struct ofp_action_header { @@ -553,7 +560,7 @@ struct ofp_flow_mod { uint16_t priority; /* Priority level of flow entry. */ uint32_t buffer_id; /* Buffered packet to apply to (or -1). Not meaningful for OFPFC_DELETE*. */ - uint16_t out_port; /* For OFPFC_DELETE* commands, require + uint16_t out_port; /* For OFPFC_DELETE* commands, require matching entries to include this as an output port. A value of OFPP_NONE indicates no restriction. */ @@ -596,7 +603,8 @@ enum ofp_error_type { OFPET_HELLO_FAILED, /* Hello protocol failed. */ OFPET_BAD_REQUEST, /* Request was not understood. */ OFPET_BAD_ACTION, /* Error in action description. */ - OFPET_FLOW_MOD_FAILED /* Problem modifying flow entry. */ + OFPET_FLOW_MOD_FAILED, /* Problem modifying flow entry. */ + OFPET_QUEUE_OP_FAILED /* Queue operation failed. */ }; /* ofp_error_msg 'code' values for OFPET_HELLO_FAILED. 'data' contains an @@ -627,7 +635,8 @@ enum ofp_bad_action_code { OFPBAC_BAD_VENDOR_TYPE, /* Unknown action type for vendor id. */ OFPBAC_BAD_OUT_PORT, /* Problem validating output action. */ OFPBAC_BAD_ARGUMENT, /* Bad action argument. */ - OFPBAC_EPERM /* Permissions error. */ + OFPBAC_EPERM, /* Permissions error. */ + OFPBAC_BAD_QUEUE /* Problem validating output queue. */ }; /* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains @@ -641,6 +650,14 @@ enum ofp_flow_mod_failed_code { * timeout. */ }; +/* ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains + * at least the first 64 bytes of the failed request */ +enum ofp_queue_op_failed_code { + OFPQOFC_BAD_PORT, /* Invalid port (or port does not exist). */ + OFPQOFC_BAD_QUEUE, /* Queue does not exist. */ + OFPQOFC_EPERM /* Permissions error. */ +}; + /* OFPT_ERROR: Error message (datapath -> controller). */ struct ofp_error_msg { struct ofp_header header; @@ -678,6 +695,11 @@ enum ofp_stats_types { * The reply body is an array of struct ofp_port_stats. */ OFPST_PORT, + /* Queue statistics for a port + * The request body defines the port + * The reply body is an array of struct ofp_queue_stats */ + OFPST_QUEUE, + /* Vendor extension. * The request and reply bodies begin with a 32-bit vendor ID, which takes * the same form as in "struct ofp_vendor_header". The request and reply @@ -770,7 +792,7 @@ OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 24); /* Body of reply to OFPST_TABLE request. */ struct ofp_table_stats { - uint8_t table_id; /* Identifier of table. Lower numbered tables + uint8_t table_id; /* Identifier of table. Lower numbered tables are consulted first. */ uint8_t pad[3]; /* Align to 32-bits. */ char name[OFP_MAX_TABLE_NAME_LEN]; @@ -820,4 +842,87 @@ struct ofp_vendor_header { }; OFP_ASSERT(sizeof(struct ofp_vendor_header) == 12); +/* All ones is used to indicate all queues in a port (for stats retrieval). */ +#define OFPQ_ALL 0xffffffff + +/* Min rate > 1000 means not configured. */ +#define OFPQ_MIN_RATE_UNCFG 0xffff + +enum ofp_queue_properties { + OFPQT_NONE = 0, /* No property defined for queue (default). */ + OFPQT_MIN_RATE, /* Minimum datarate guaranteed. */ + /* Other types should be added here + * (i.e. max rate, precedence, etc). */ +}; + +/* Common description for a queue. */ +struct ofp_queue_prop_header { + uint16_t property; /* One of OFPQT_. */ + uint16_t len; /* Length of property, including this header. */ + uint8_t pad[4]; /* 64-bit alignemnt. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_header) == 8); + +/* Min-Rate queue property description. */ +struct ofp_queue_prop_min_rate { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16. */ + uint16_t rate; /* In 1/10 of a percent; >1000 -> disabled. */ + uint8_t pad[6]; /* 64-bit alignment */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16); + +/* Full description for a queue. */ +struct ofp_packet_queue { + uint32_t queue_id; /* id for the specific queue. */ + uint16_t len; /* Length in bytes of this queue desc. */ + uint8_t pad[2]; /* 64-bit alignment. */ + struct ofp_queue_prop_header properties[0]; /* List of properties. */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_queue) == 8); + +/* Query for port queue configuration. */ +struct ofp_queue_get_config_request { + struct ofp_header header; + uint16_t port; /* Port to be queried. Should refer + to a valid physical port (i.e. < OFPP_MAX) */ + uint8_t pad[2]; /* 32-bit alignment. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_request) == 12); + +/* Queue configuration for a given port. */ +struct ofp_queue_get_config_reply { + struct ofp_header header; + uint16_t port; + uint8_t pad[6]; + struct ofp_packet_queue queues[]; /* List of configured queues. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_reply) == 16); + +/* OFPAT_ENQUEUE action struct: send packets to given queue on port. */ +struct ofp_action_enqueue { + uint16_t type; /* OFPAT_ENQUEUE. */ + uint16_t len; /* Len is 12. */ + uint16_t port; /* Port that queue belongs. */ + uint8_t pad[6]; /* Pad for 64-bit alignment. */ + uint32_t queue_id; /* Where to enqueue the packets. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_enqueue) == 16); + +struct ofp_queue_stats_request { + uint16_t port_no; /* All ports if OFPT_ALL. */ + uint8_t pad[2]; /* Align to 32-bits. */ + uint32_t queue_id; /* All queues if OFPQ_ALL. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); + +struct ofp_queue_stats { + uint16_t port_no; + uint8_t pad[2]; /* Align to 32-bits. */ + uint32_t queue_id; /* Queue i.d */ + uint64_t tx_bytes; /* Number of transmitted bytes. */ + uint64_t tx_packets; /* Number of transmitted packets. */ + uint64_t tx_errors; /* Number of packets dropped due to overrun. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats) == 32); + #endif /* openflow/openflow.h */