--- /dev/null
+#! /usr/bin/python
+
+import sys
+import os.path
+import re
+
+line = ""
+
+OFP10_VERSION = 0x01
+OFP11_VERSION = 0x02
+OFP12_VERSION = 0x03
+OFP13_VERSION = 0x04
+
+NX_VENDOR_ID = 0x00002320
+
+OFPT_VENDOR = 4
+OFPT10_STATS_REQUEST = 16
+OFPT10_STATS_REPLY = 17
+OFPT11_STATS_REQUEST = 18
+OFPT11_STATS_REPLY = 19
+OFPST_VENDOR = 0xffff
+
+version_map = {"1.0": (OFP10_VERSION, OFP10_VERSION),
+ "1.1": (OFP11_VERSION, OFP11_VERSION),
+ "1.2": (OFP12_VERSION, OFP12_VERSION),
+ "1.3": (OFP13_VERSION, OFP13_VERSION),
+ "1.0+": (OFP10_VERSION, OFP13_VERSION),
+ "1.1+": (OFP11_VERSION, OFP13_VERSION),
+ "1.2+": (OFP12_VERSION, OFP13_VERSION),
+ "1.3+": (OFP13_VERSION, OFP13_VERSION),
+ "1.0-1.1": (OFP10_VERSION, OFP11_VERSION)}
+
+def get_line():
+ global line
+ global line_number
+ line = input_file.readline()
+ line_number += 1
+ if line == "":
+ fatal("unexpected end of input")
+
+n_errors = 0
+def error(msg):
+ global n_errors
+ sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
+ n_errors += 1
+
+def fatal(msg):
+ error(msg)
+ sys.exit(1)
+
+def usage():
+ argv0 = os.path.basename(sys.argv[0])
+ print '''\
+%(argv0)s, for extracting OpenFlow message types from header files
+usage: %(argv0)s INPUT OUTPUT
+ where INPUT is the name of the input header file
+ and OUTPUT is the output file name.
+Despite OUTPUT, the output is written to stdout, and the OUTPUT argument
+only controls #line directives in the output.\
+''' % {"argv0": argv0}
+ sys.exit(0)
+
+def make_sizeof(s):
+ m = re.match(r'(.*) up to (.*)', s)
+ if m:
+ struct, member = m.groups()
+ return "offsetof(%s, %s)" % (struct, member)
+ else:
+ return "sizeof(%s)" % s
+
+def extract_ofp_msgs(output_file_name):
+ raw_types = []
+
+ all_hdrs = {}
+ all_raws = {}
+ all_raws_order = []
+
+ while True:
+ get_line()
+ if re.match('enum ofpraw', line):
+ break
+
+ while True:
+ get_line()
+ first_line_number = line_number
+ here = '%s:%d' % (file_name, line_number)
+ if (line.startswith('/*')
+ or line.startswith(' *')
+ or not line
+ or line.isspace()):
+ continue
+ elif re.match('}', line):
+ break
+
+ if not line.lstrip().startswith('/*'):
+ fatal("unexpected syntax between ofpraw types")
+
+ comment = line.lstrip()[2:].strip()
+ while not comment.endswith('*/'):
+ get_line()
+ if line.startswith('/*') or not line or line.isspace():
+ fatal("unexpected syntax within error")
+ comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
+ comment = comment[:-2].rstrip()
+
+ m = re.match(r'([A-Z]+) ([-.+\d]+) \((\d+)\): ([^.]+)\.$', comment)
+ if not m:
+ fatal("unexpected syntax between messages")
+ type_, versions, number, contents = m.groups()
+ number = int(number)
+
+ get_line()
+ m = re.match('\s+(?:OFPRAW_%s)(\d*)_([A-Z0-9_]+),?$' % type_,
+ line)
+ if not m:
+ fatal("syntax error expecting OFPRAW_ enum")
+ vinfix, name = m.groups()
+ rawname = 'OFPRAW_%s%s_%s' % (type_, vinfix, name)
+
+ min_version, max_version = version_map[versions]
+
+ human_name = '%s_%s' % (type_, name)
+ if type_.endswith('ST'):
+ if rawname.endswith('_REQUEST'):
+ human_name = human_name[:-8] + " request"
+ elif rawname.endswith('_REPLY'):
+ human_name = human_name[:-6] + " reply"
+ else:
+ fatal("%s messages are statistics but %s doesn't end "
+ "in _REQUEST or _REPLY" % (type_, rawname))
+
+ these_hdrs = []
+ for version in range(min_version, max_version + 1):
+ if type_ == 'OFPT':
+ if number == OFPT_VENDOR:
+ fatal("OFPT (%d) is used for vendor extensions"
+ % number)
+ elif (version == OFP10_VERSION
+ and (number == OFPT10_STATS_REQUEST
+ or number == OFPT10_STATS_REPLY)):
+ fatal("OFPT 1.0 (%d) is used for stats messages"
+ % number)
+ elif (version != OFP10_VERSION
+ and (number == OFPT11_STATS_REQUEST
+ or number == OFPT11_STATS_REPLY)):
+ fatal("OFPT 1.1+ (%d) is used for stats messages"
+ % number)
+ hdrs = (version, number, 0, 0, 0)
+ elif type_ == 'OFPST' and name.endswith('_REQUEST'):
+ if version == OFP10_VERSION:
+ hdrs = (version, OFPT10_STATS_REQUEST, number, 0, 0)
+ else:
+ hdrs = (version, OFPT11_STATS_REQUEST, number, 0, 0)
+ elif type_ == 'OFPST' and name.endswith('_REPLY'):
+ if version == OFP10_VERSION:
+ hdrs = (version, OFPT10_STATS_REPLY, number, 0, 0)
+ else:
+ hdrs = (version, OFPT11_STATS_REPLY, number, 0, 0)
+ elif type_ == 'NXT':
+ hdrs = (version, OFPT_VENDOR, 0, NX_VENDOR_ID, number)
+ elif type_ == 'NXST' and name.endswith('_REQUEST'):
+ if version == OFP10_VERSION:
+ hdrs = (version, OFPT10_STATS_REQUEST, OFPST_VENDOR,
+ NX_VENDOR_ID, number)
+ else:
+ hdrs = (version, OFPT11_STATS_REQUEST, OFPST_VENDOR,
+ NX_VENDOR_ID, number)
+ elif type_ == 'NXST' and name.endswith('_REPLY'):
+ if version == OFP10_VERSION:
+ hdrs = (version, OFPT10_STATS_REPLY, OFPST_VENDOR,
+ NX_VENDOR_ID, number)
+ else:
+ hdrs = (version, OFPT11_STATS_REPLY, OFPST_VENDOR,
+ NX_VENDOR_ID, number)
+ else:
+ fatal("type '%s' unknown" % type_)
+
+ if hdrs in all_hdrs:
+ error("Duplicate message definition for %s." % str(hdrs))
+ sys.stderr.write("%s: Here is the location "
+ "of the previous definition.\n"
+ % (all_hdrs[hdrs]))
+ all_hdrs[hdrs] = here
+ these_hdrs.append(hdrs)
+
+ extra_multiple = '0'
+ if contents == 'void':
+ min_body = '0'
+ else:
+ min_body_elem = []
+ for c in [s.strip() for s in contents.split(",")]:
+ if c.endswith('[]'):
+ if extra_multiple == '0':
+ extra_multiple = make_sizeof(c[:-2])
+ else:
+ error("Cannot have multiple [] elements")
+ else:
+ min_body_elem.append(c)
+
+ if min_body_elem:
+ min_body = " + ".join([make_sizeof(s)
+ for s in min_body_elem])
+ else:
+ if extra_multiple == '0':
+ error("Must specify contents (use 'void' if empty)")
+ min_body = 0
+
+ if rawname in all_raws:
+ fatal("%s: Duplicate name" % rawname)
+
+ all_raws[rawname] = {"hdrs": these_hdrs,
+ "min_version": min_version,
+ "max_version": max_version,
+ "min_body": min_body,
+ "extra_multiple": extra_multiple,
+ "type": type_,
+ "human_name": human_name,
+ "line": first_line_number}
+ all_raws_order.append(rawname)
+
+ continue
+
+ while True:
+ get_line()
+ if re.match('enum ofptype', line):
+ break
+
+ while True:
+ get_line()
+ if re.match(r'\s*/?\*', line) or line.isspace():
+ continue
+ elif re.match('}', line):
+ break
+
+ if not re.match(r'\s*OFPTYPE_.*/\*', line):
+ fatal("unexpected syntax between OFPTYPE_ definitions")
+
+ syntax = line.strip()
+ while not syntax.endswith('*/'):
+ get_line()
+ if not line.strip().startswith('*'):
+ fatal("unexpected syntax within OFPTYPE_ definition")
+ syntax += ' %s' % line.strip().lstrip('* \t')
+ syntax = syntax.strip()
+
+ m = re.match(r'(OFPTYPE_[A-Z0-9_]+),\s*/\* (.*) \*/', syntax)
+ if not m:
+ fatal("syntax error in OFPTYPE_ definition")
+
+ ofptype, raws_ = m.groups()
+ raws = [s.rstrip('.') for s in raws_.split()]
+ for raw in raws:
+ if not re.match('OFPRAW_[A-Z0-9_]+$', raw):
+ fatal("%s: invalid OFPRAW_* name syntax" % raw)
+ if raw not in all_raws:
+ fatal("%s: not a declared OFPRAW_* name" % raw)
+ if "ofptype" in all_raws[raw]:
+ fatal("%s: already part of %s"
+ % (raw, all_raws[raw]["ofptype"]))
+ all_raws[raw]["ofptype"] = ofptype
+
+ input_file.close()
+
+ if n_errors:
+ sys.exit(1)
+
+ output = []
+ output.append("/* Generated automatically; do not modify! "
+ "-*- buffer-read-only: t -*- */")
+ output.append("")
+
+ for raw in all_raws_order:
+ r = all_raws[raw]
+ output.append("static struct raw_instance %s_instances[] = {"
+ % raw.lower())
+ for hdrs in r['hdrs']:
+ output.append(" { {0, NULL}, {%d, %d, %d, 0x%x, %d}, %s, 0 },"
+ % (hdrs + (raw,)))
+
+ output.append("};")
+
+ output.append("")
+
+ output.append("static struct raw_info raw_infos[] = {")
+ for raw in all_raws_order:
+ r = all_raws[raw]
+ if "ofptype" not in r:
+ error("%s: no defined OFPTYPE_" % raw)
+ continue
+ output.append(" {")
+ output.append(" %s_instances," % raw.lower())
+ output.append(" %d, %d," % (r["min_version"], r["max_version"]))
+ output.append("#line %s \"%s\"" % (r["line"], file_name))
+ output.append(" %s," % r["min_body"])
+ output.append("#line %s \"%s\"" % (r["line"], file_name))
+ output.append(" %s," % r["extra_multiple"])
+ output.append("#line %s \"%s\"" % (len(output) + 2, output_file_name))
+ output.append(" %s," % r["ofptype"])
+ output.append(" \"%s\"," % r["human_name"])
+ output.append(" },")
+
+ if r['type'].endswith("ST"):
+ for hdrs in r['hdrs']:
+ op_hdrs = list(hdrs)
+ if hdrs[0] == OFP10_VERSION:
+ if hdrs[1] == OFPT10_STATS_REQUEST:
+ op_hdrs[1] = OFPT10_STATS_REPLY
+ elif hdrs[1] == OFPT10_STATS_REPLY:
+ op_hdrs[1] = OFPT10_STATS_REQUEST
+ else:
+ assert False
+ else:
+ if hdrs[1] == OFPT11_STATS_REQUEST:
+ op_hdrs[1] = OFPT11_STATS_REPLY
+ elif hdrs[1] == OFPT11_STATS_REPLY:
+ op_hdrs[1] = OFPT11_STATS_REQUEST
+ else:
+ assert False
+ if tuple(op_hdrs) not in all_hdrs:
+ if r["human_name"].endswith("request"):
+ fatal("%s has no corresponding reply"
+ % r["human_name"])
+ else:
+ fatal("%s has no corresponding request"
+ % r["human_name"])
+ output.append("};")
+
+ if n_errors:
+ sys.exit(1)
+
+ return output
+
+
+if __name__ == '__main__':
+ if '--help' in sys.argv:
+ usage()
+ elif len(sys.argv) != 3:
+ sys.stderr.write("exactly one non-option arguments required; "
+ "use --help for help\n")
+ sys.exit(1)
+ else:
+ global file_name
+ global input_file
+ global line_number
+ file_name = sys.argv[1]
+ input_file = open(file_name)
+ line_number = 0
+
+ for line in extract_ofp_msgs(sys.argv[2]):
+ print line
+
struct nicira_header {
struct ofp_header header;
ovs_be32 vendor; /* NX_VENDOR_ID. */
- ovs_be32 subtype; /* One of NXT_* below. */
+ ovs_be32 subtype; /* See the NXT numbers in ofp-msgs.h. */
};
OFP_ASSERT(sizeof(struct nicira_header) == 16);
-/* Values for the 'subtype' member of struct nicira_header. */
-enum nicira_type {
- /* No longer used. */
- NXT_STATUS_REQUEST__OBSOLETE = 0,
- NXT_STATUS_REPLY__OBSOLETE = 1,
- NXT_ACT_SET_CONFIG__OBSOLETE = 2,
- NXT_ACT_GET_CONFIG__OBSOLETE = 3,
- NXT_COMMAND_REQUEST__OBSOLETE = 4,
- NXT_COMMAND_REPLY__OBSOLETE = 5,
- NXT_FLOW_END_CONFIG__OBSOLETE = 6,
- NXT_FLOW_END__OBSOLETE = 7,
- NXT_MGMT__OBSOLETE = 8,
- NXT_TUN_ID_FROM_COOKIE__OBSOLETE = 9,
-
- /* Controller role support. The request body is struct nx_role_request.
- * The reply echos the request. */
- NXT_ROLE_REQUEST = 10,
- NXT_ROLE_REPLY = 11,
-
- /* Flexible flow specification (aka NXM = Nicira Extended Match). */
- NXT_SET_FLOW_FORMAT = 12, /* Set flow format. */
- NXT_FLOW_MOD = 13, /* Analogous to OFPT_FLOW_MOD. */
- NXT_FLOW_REMOVED = 14, /* Analogous to OFPT_FLOW_REMOVED. */
-
- /* Use the upper 8 bits of the 'command' member in struct ofp_flow_mod to
- * designate the table to which a flow is to be added? See the big comment
- * on struct nx_flow_mod_table_id for more information. */
- NXT_FLOW_MOD_TABLE_ID = 15,
-
- /* Alternative PACKET_IN message formats. */
- NXT_SET_PACKET_IN_FORMAT = 16, /* Set Packet In format. */
- NXT_PACKET_IN = 17, /* Nicira Packet In. */
-
- /* Are the idle_age and hard_age members in struct nx_flow_stats supported?
- * If so, the switch does not reply to this message (which consists only of
- * a "struct nicira_header"). If not, the switch sends an error reply. */
- NXT_FLOW_AGE = 18,
-
- NXT_SET_ASYNC_CONFIG = 19, /* struct nx_async_config. */
- NXT_SET_CONTROLLER_ID = 20, /* struct nx_controller_id. */
-
- /* Flow table monitoring (see also NXST_FLOW_MONITOR). */
- NXT_FLOW_MONITOR_CANCEL = 21, /* struct nx_flow_monitor_cancel. */
- NXT_FLOW_MONITOR_PAUSED = 22, /* struct nicira_header. */
- NXT_FLOW_MONITOR_RESUMED = 23, /* struct nicira_header. */
-};
-
-/* Header for Nicira vendor stats request and reply messages. */
-struct nicira_stats_msg {
- struct ofp_vendor_stats_msg vsm; /* Vendor NX_VENDOR_ID. */
+/* Header for Nicira vendor stats request and reply messages in OpenFlow
+ * 1.0. */
+struct nicira10_stats_msg {
+ struct ofp10_vendor_stats_msg vsm; /* Vendor NX_VENDOR_ID. */
ovs_be32 subtype; /* One of NXST_* below. */
uint8_t pad[4]; /* Align to 64-bits. */
};
-OFP_ASSERT(sizeof(struct nicira_stats_msg) == 24);
+OFP_ASSERT(sizeof(struct nicira10_stats_msg) == 24);
-/* Values for the 'subtype' member of struct nicira_stats_msg. */
-enum nicira_stats_type {
- /* Flexible flow specification (aka NXM = Nicira Extended Match). */
- NXST_FLOW, /* Analogous to OFPST_FLOW. */
- NXST_AGGREGATE, /* Analogous to OFPST_AGGREGATE. */
-
- /* Flow table monitoring. */
- NXST_FLOW_MONITOR,
+/* Header for Nicira vendor stats request and reply messages in OpenFlow
+ * 1.1. */
+struct nicira11_stats_msg {
+ struct ofp11_vendor_stats_msg vsm; /* Vendor NX_VENDOR_ID. */
+ ovs_be32 subtype; /* One of NXST_* below. */
};
+OFP_ASSERT(sizeof(struct nicira11_stats_msg) == 24);
/* Fields to use when hashing flows. */
enum nx_hash_fields {
* table match, then none is modified or deleted.
*/
struct nx_flow_mod_table_id {
- struct ofp_header header;
- ovs_be32 vendor; /* NX_VENDOR_ID. */
- ovs_be32 subtype; /* NXT_FLOW_MOD_TABLE_ID. */
uint8_t set; /* Nonzero to enable, zero to disable. */
uint8_t pad[7];
};
-OFP_ASSERT(sizeof(struct nx_flow_mod_table_id) == 24);
+OFP_ASSERT(sizeof(struct nx_flow_mod_table_id) == 8);
enum nx_packet_in_format {
NXPIF_OPENFLOW10 = 0, /* Standard OpenFlow 1.0 compatible. */
/* NXT_SET_PACKET_IN_FORMAT request. */
struct nx_set_packet_in_format {
- struct nicira_header nxh;
ovs_be32 format; /* One of NXPIF_*. */
};
-OFP_ASSERT(sizeof(struct nx_set_packet_in_format) == 20);
+OFP_ASSERT(sizeof(struct nx_set_packet_in_format) == 4);
/* NXT_PACKET_IN (analogous to OFPT_PACKET_IN).
*
* The 'cookie' and 'table_id' fields have no meaning when 'reason' is
* OFPR_NO_MATCH. In this case they should be set to 0. */
struct nx_packet_in {
- struct nicira_header nxh;
ovs_be32 buffer_id; /* ID assigned by datapath. */
ovs_be16 total_len; /* Full length of frame. */
uint8_t reason; /* Reason packet is sent (one of OFPR_*). */
/* uint8_t pad[2]; */ /* Align to 64 bit + 16 bit. */
/* uint8_t data[0]; */ /* Ethernet frame. */
};
-OFP_ASSERT(sizeof(struct nx_packet_in) == 40);
+OFP_ASSERT(sizeof(struct nx_packet_in) == 24);
/* Configures the "role" of the sending controller. The default role is:
*
* messages, but they do receive OFPT_PORT_STATUS messages.
*/
struct nx_role_request {
- struct nicira_header nxh;
ovs_be32 role; /* One of NX_ROLE_*. */
};
-OFP_ASSERT(sizeof(struct nx_role_request) == 20);
+OFP_ASSERT(sizeof(struct nx_role_request) == 4);
enum nx_role {
NX_ROLE_OTHER, /* Default role, full access. */
* miss_send_len from default of zero to OFP_DEFAULT_MISS_SEND_LEN (128).
*/
struct nx_async_config {
- struct nicira_header nxh;
ovs_be32 packet_in_mask[2]; /* Bitmasks of OFPR_* values. */
ovs_be32 port_status_mask[2]; /* Bitmasks of OFPRR_* values. */
ovs_be32 flow_removed_mask[2]; /* Bitmasks of OFPPR_* values. */
};
-OFP_ASSERT(sizeof(struct nx_async_config) == 40);
+OFP_ASSERT(sizeof(struct nx_async_config) == 24);
\f
/* Nicira vendor flow actions. */
/* NXT_SET_FLOW_FORMAT request. */
struct nx_set_flow_format {
- struct nicira_header nxh;
ovs_be32 format; /* One of NXFF_*. */
};
-OFP_ASSERT(sizeof(struct nx_set_flow_format) == 20);
+OFP_ASSERT(sizeof(struct nx_set_flow_format) == 4);
/* NXT_FLOW_MOD (analogous to OFPT_FLOW_MOD).
*
* is used only to add or modify flow cookies.
*/
struct nx_flow_mod {
- struct nicira_header nxh;
ovs_be64 cookie; /* Opaque controller-issued identifier. */
ovs_be16 command; /* One of OFPFC_*. */
ovs_be16 idle_timeout; /* Idle time before discarding (seconds). */
* multiple of 8).
*/
};
-OFP_ASSERT(sizeof(struct nx_flow_mod) == 48);
+OFP_ASSERT(sizeof(struct nx_flow_mod) == 32);
/* NXT_FLOW_REMOVED (analogous to OFPT_FLOW_REMOVED). */
struct nx_flow_removed {
- struct nicira_header nxh;
ovs_be64 cookie; /* Opaque controller-issued identifier. */
ovs_be16 priority; /* Priority level of flow entry. */
uint8_t reason; /* One of OFPRR_*. */
* - Exactly (match_len + 7)/8*8 - match_len (between 0 and 7) bytes of
* all-zero bytes. */
};
-OFP_ASSERT(sizeof(struct nx_flow_removed) == 56);
+OFP_ASSERT(sizeof(struct nx_flow_removed) == 40);
/* Nicira vendor stats request of type NXST_FLOW (analogous to OFPST_FLOW
* request).
* NXM_NX_COOKIE and NXM_NX_COOKIE_W matches.
*/
struct nx_flow_stats_request {
- struct nicira_stats_msg nsm;
ovs_be16 out_port; /* Require matching entries to include this
as an output port. A value of OFPP_NONE
indicates no restriction. */
* message.
*/
};
-OFP_ASSERT(sizeof(struct nx_flow_stats_request) == 32);
+OFP_ASSERT(sizeof(struct nx_flow_stats_request) == 8);
/* Body for Nicira vendor stats reply of type NXST_FLOW (analogous to
* OFPST_FLOW reply).
/* Nicira vendor stats request of type NXST_AGGREGATE (analogous to
* OFPST_AGGREGATE request). */
struct nx_aggregate_stats_request {
- struct nicira_stats_msg nsm;
ovs_be16 out_port; /* Require matching entries to include this
as an output port. A value of OFPP_NONE
indicates no restriction. */
* message.
*/
};
-OFP_ASSERT(sizeof(struct nx_aggregate_stats_request) == 32);
+OFP_ASSERT(sizeof(struct nx_aggregate_stats_request) == 8);
/* Body for nicira_stats_msg reply of type NXST_AGGREGATE (analogous to
* OFPST_AGGREGATE reply). */
struct nx_aggregate_stats_reply {
- struct nicira_stats_msg nsm;
ovs_be64 packet_count; /* Number of packets, UINT64_MAX if unknown. */
ovs_be64 byte_count; /* Number of bytes, UINT64_MAX if unknown. */
ovs_be32 flow_count; /* Number of flows. */
uint8_t pad[4]; /* Align to 64 bits. */
};
-OFP_ASSERT(sizeof(struct nx_aggregate_stats_reply) == 48);
+OFP_ASSERT(sizeof(struct nx_aggregate_stats_reply) == 24);
\f
/* NXT_SET_CONTROLLER_ID.
*
* The NXAST_CONTROLLER action is the only current user of controller
* connection IDs. */
struct nx_controller_id {
- struct nicira_header nxh;
uint8_t zero[6]; /* Must be zero. */
ovs_be16 controller_id; /* New controller connection ID. */
};
-OFP_ASSERT(sizeof(struct nx_controller_id) == 24);
+OFP_ASSERT(sizeof(struct nx_controller_id) == 8);
/* Action structure for NXAST_CONTROLLER.
*
};
OFP_ASSERT(sizeof(struct nx_flow_update_abbrev) == 8);
-/* Used by a controller to cancel an outstanding monitor. */
+/* NXT_FLOW_MONITOR_CANCEL.
+ *
+ * Used by a controller to cancel an outstanding monitor. */
struct nx_flow_monitor_cancel {
- struct nicira_header nxh; /* Type NXT_FLOW_MONITOR_CANCEL. */
ovs_be32 id; /* 'id' from nx_flow_monitor_request. */
};
-OFP_ASSERT(sizeof(struct nx_flow_monitor_cancel) == 20);
+OFP_ASSERT(sizeof(struct nx_flow_monitor_cancel) == 4);
#endif /* openflow/nicira-ext.h */
OFPP_NONE = 0xffff /* Not associated with a physical port. */
};
-/* OpenFlow 1.0 specific message types, in addition to the common message
- * types. */
-enum ofp10_type {
- /* Controller command messages. */
- OFPT10_PORT_MOD = 15, /* Controller/switch message */
-
- /* Statistics messages. */
- OFPT10_STATS_REQUEST, /* Controller/switch message */
- OFPT10_STATS_REPLY, /* Controller/switch message */
-
- /* Barrier messages. */
- OFPT10_BARRIER_REQUEST, /* Controller/switch message */
- OFPT10_BARRIER_REPLY, /* Controller/switch message */
-
- /* Queue Configuration messages. */
- OFPT10_QUEUE_GET_CONFIG_REQUEST, /* Controller/switch message */
- OFPT10_QUEUE_GET_CONFIG_REPLY /* Controller/switch message */
-};
-
-/* OFPT_HELLO. This message has an empty body, but implementations must
- * ignore any data included in the body, to allow for future extensions. */
-struct ofp_hello {
- struct ofp_header header;
-};
-
#define OFP_DEFAULT_MISS_SEND_LEN 128
enum ofp_config_flags {
/* Switch configuration. */
struct ofp_switch_config {
- struct ofp_header header;
ovs_be16 flags; /* OFPC_* flags. */
ovs_be16 miss_send_len; /* Max bytes of new flow that datapath should
send to the controller. */
};
-OFP_ASSERT(sizeof(struct ofp_switch_config) == 12);
+OFP_ASSERT(sizeof(struct ofp_switch_config) == 4);
/* OpenFlow 1.0 specific capabilities supported by the datapath (struct
* ofp_switch_features, member capabilities). */
/* Modify behavior of the physical port */
struct ofp10_port_mod {
- struct ofp_header header;
ovs_be16 port_no;
uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
configurable. This is used to
bits to prevent any action taking place. */
uint8_t pad[4]; /* Pad to 64-bits. */
};
-OFP_ASSERT(sizeof(struct ofp10_port_mod) == 32);
+OFP_ASSERT(sizeof(struct ofp10_port_mod) == 24);
/* Query for port queue configuration. */
struct ofp10_queue_get_config_request {
- struct ofp_header header;
ovs_be16 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 ofp10_queue_get_config_request) == 12);
+OFP_ASSERT(sizeof(struct ofp10_queue_get_config_request) == 4);
/* Queue configuration for a given port. */
struct ofp10_queue_get_config_reply {
- struct ofp_header header;
ovs_be16 port;
uint8_t pad[6];
/* struct ofp10_packet_queue queues[0]; List of configured queues. */
};
-OFP_ASSERT(sizeof(struct ofp10_queue_get_config_reply) == 16);
+OFP_ASSERT(sizeof(struct ofp10_queue_get_config_reply) == 8);
/* Packet received on port (datapath -> controller). */
struct ofp_packet_in {
- struct ofp_header header;
ovs_be32 buffer_id; /* ID assigned by datapath. */
ovs_be16 total_len; /* Full length of frame. */
ovs_be16 in_port; /* Port on which frame was received. */
offsetof(struct ofp_packet_in, data) ==
sizeof(struct ofp_packet_in) - 2. */
};
-OFP_ASSERT(sizeof(struct ofp_packet_in) == 20);
+OFP_ASSERT(sizeof(struct ofp_packet_in) == 12);
enum ofp10_action_type {
OFPAT10_OUTPUT, /* Output to switch port. */
/* Send packet (controller -> datapath). */
struct ofp_packet_out {
- struct ofp_header header;
ovs_be32 buffer_id; /* ID assigned by datapath or UINT32_MAX. */
ovs_be16 in_port; /* Packet's input port (OFPP_NONE if none). */
ovs_be16 actions_len; /* Size of action array in bytes. */
* of the message length.
*/
};
-OFP_ASSERT(sizeof(struct ofp_packet_out) == 16);
+OFP_ASSERT(sizeof(struct ofp_packet_out) == 8);
enum ofp_flow_mod_command {
OFPFC_ADD, /* New flow. */
/* Flow setup and teardown (controller -> datapath). */
struct ofp_flow_mod {
- struct ofp_header header;
struct ofp10_match match; /* Fields to match */
ovs_be64 cookie; /* Opaque controller-issued identifier. */
from the length field in the
header. */
};
-OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72);
+OFP_ASSERT(sizeof(struct ofp_flow_mod) == 64);
/* Flow removed (datapath -> controller). */
struct ofp_flow_removed {
- struct ofp_header header;
struct ofp10_match match; /* Description of fields. */
ovs_be64 cookie; /* Opaque controller-issued identifier. */
ovs_be64 packet_count;
ovs_be64 byte_count;
};
-OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88);
+OFP_ASSERT(sizeof(struct ofp_flow_removed) == 80);
/* OFPT_ERROR: Error message (datapath -> controller). */
struct ofp_error_msg {
- struct ofp_header header;
-
ovs_be16 type;
ovs_be16 code;
uint8_t data[0]; /* Variable-length data. Interpreted based
on the type and code. */
};
-OFP_ASSERT(sizeof(struct ofp_error_msg) == 12);
+OFP_ASSERT(sizeof(struct ofp_error_msg) == 4);
/* Statistics request or reply message. */
struct ofp_stats_msg {
#define DESC_STR_LEN 256
#define SERIAL_NUM_LEN 32
-/* Reply to OFPST_DESC request. Each entry is a NULL-terminated ASCII
+/* Body of reply to OFPST_DESC request. Each entry is a NULL-terminated ASCII
* string. */
struct ofp_desc_stats {
- struct ofp_stats_msg osm;
char mfr_desc[DESC_STR_LEN]; /* Manufacturer description. */
char hw_desc[DESC_STR_LEN]; /* Hardware description. */
char sw_desc[DESC_STR_LEN]; /* Software description. */
char dp_desc[DESC_STR_LEN]; /* Human readable description of
the datapath. */
};
-OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1068);
+OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1056);
/* Stats request of type OFPST_AGGREGATE or OFPST_FLOW. */
struct ofp_flow_stats_request {
- struct ofp_stats_msg osm;
struct ofp10_match match; /* Fields to match. */
uint8_t table_id; /* ID of table to read (from ofp_table_stats)
or 0xff for all tables. */
as an output port. A value of OFPP_NONE
indicates no restriction. */
};
-OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 56);
+OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44);
/* Body of reply to OFPST_FLOW request. */
struct ofp_flow_stats {
/* Reply to OFPST_AGGREGATE request. */
struct ofp_aggregate_stats_reply {
- struct ofp_stats_msg osm;
ovs_32aligned_be64 packet_count; /* Number of packets in flows. */
ovs_32aligned_be64 byte_count; /* Number of bytes in flows. */
ovs_be32 flow_count; /* Number of flows. */
uint8_t pad[4]; /* Align to 64 bits. */
};
-OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 36);
+OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 24);
/* Body of reply to OFPST_TABLE request. */
struct ofp_table_stats {
/* Stats request of type OFPST_PORT. */
struct ofp_port_stats_request {
- struct ofp_stats_msg osm;
ovs_be16 port_no; /* OFPST_PORT message may request statistics
for a single port (specified with port_no)
or for all ports (port_no == OFPP_NONE). */
uint8_t pad[6];
};
-OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 20);
+OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8);
/* Body of reply to OFPST_PORT request. If a counter is unsupported, set
* the field to all ones. */
/* Body for stats request of type OFPST_QUEUE. */
struct ofp_queue_stats_request {
- struct ofp_stats_msg osm;
ovs_be16 port_no; /* All ports if OFPP_ALL. */
uint8_t pad[2]; /* Align to 32-bits. */
ovs_be32 queue_id; /* All queues if OFPQ_ALL. */
};
-OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 20);
+OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8);
/* Body for stats reply of type OFPST_QUEUE consists of an array of this
* structure type. */
OFP_ASSERT(sizeof(struct ofp_queue_stats) == 32);
/* Vendor extension stats message. */
-struct ofp_vendor_stats_msg {
+struct ofp10_vendor_stats_msg {
struct ofp_stats_msg osm; /* Type OFPST_VENDOR. */
ovs_be32 vendor; /* Vendor ID:
* - MSB 0: low-order bytes are IEEE OUI.
* consortium. */
/* Followed by vendor-defined arbitrary additional data. */
};
-OFP_ASSERT(sizeof(struct ofp_vendor_stats_msg) == 16);
+OFP_ASSERT(sizeof(struct ofp10_vendor_stats_msg) == 16);
/* Vendor extension. */
struct ofp_vendor_header {
#define OFPP11_MAX 0xffffff00
#define OFPP11_OFFSET (OFPP11_MAX - OFPP_MAX)
-/* OpenFlow 1.1 specific message types, in addition to the common message
- * types. */
-enum ofp11_type {
- /* Controller command messages. */
- OFPT11_GROUP_MOD = 15, /* Controller/switch message */
- OFPT11_PORT_MOD, /* Controller/switch message */
- OFPT11_TABLE_MOD, /* Controller/switch message */
-
- /* Statistics messages. */
- OFPT11_STATS_REQUEST, /* Controller/switch message */
- OFPT11_STATS_REPLY, /* Controller/switch message */
-
- /* Barrier messages. */
- OFPT11_BARRIER_REQUEST, /* Controller/switch message */
- OFPT11_BARRIER_REPLY, /* Controller/switch message */
-
- /* Queue Configuration messages. */
- OFPT11_QUEUE_GET_CONFIG_REQUEST, /* Controller/switch message */
- OFPT11_QUEUE_GET_CONFIG_REPLY, /* Controller/switch message */
-};
-
/* OpenFlow 1.1 port config flags are just the common flags. */
#define OFPPC11_ALL \
(OFPPC_PORT_DOWN | OFPPC_NO_RECV | OFPPC_NO_FWD | OFPPC_NO_PACKET_IN)
/* Modify behavior of the physical port */
struct ofp11_port_mod {
- struct ofp_header header;
ovs_be32 port_no;
uint8_t pad[4];
uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
to prevent any action taking place. */
uint8_t pad3[4]; /* Pad to 64 bits. */
};
-OFP_ASSERT(sizeof(struct ofp11_port_mod) == 40);
+OFP_ASSERT(sizeof(struct ofp11_port_mod) == 32);
/* Group setup and teardown (controller -> datapath). */
struct ofp11_group_mod {
- struct ofp_header header;
ovs_be16 command; /* One of OFPGC_*. */
uint8_t type; /* One of OFPGT_*. */
uint8_t pad; /* Pad to 64 bits. */
/* struct ofp11_bucket buckets[0]; The bucket length is inferred from the
length field in the header. */
};
-OFP_ASSERT(sizeof(struct ofp11_group_mod) == 16);
+OFP_ASSERT(sizeof(struct ofp11_group_mod) == 8);
/* Query for port queue configuration. */
struct ofp11_queue_get_config_request {
- struct ofp_header header;
ovs_be32 port;
/* Port to be queried. Should refer
to a valid physical port (i.e. < OFPP_MAX) */
uint8_t pad[4];
};
-OFP_ASSERT(sizeof(struct ofp11_queue_get_config_request) == 16);
+OFP_ASSERT(sizeof(struct ofp11_queue_get_config_request) == 8);
/* Group commands */
enum ofp11_group_mod_command {
/* Configure/Modify behavior of a flow table */
struct ofp11_table_mod {
- struct ofp_header header;
uint8_t table_id; /* ID of the table, 0xFF indicates all tables */
uint8_t pad[3]; /* Pad to 32 bits */
ovs_be32 config; /* Bitmap of OFPTC_* flags */
};
-OFP_ASSERT(sizeof(struct ofp11_table_mod) == 16);
+OFP_ASSERT(sizeof(struct ofp11_table_mod) == 8);
/* Flags to indicate behavior of the flow table for unmatched packets.
These flags are used in ofp_table_stats messages to describe the current
/* Flow setup and teardown (controller -> datapath). */
struct ofp11_flow_mod {
- struct ofp_header header;
ovs_be64 cookie; /* Opaque controller-issued identifier. */
ovs_be64 cookie_mask; /* Mask used to restrict the cookie bits
that must match when the command is
/* Open Flow version specific match */
/* struct ofp_instruction instructions[0]; Instruction set */
};
-OFP_ASSERT(sizeof(struct ofp11_flow_mod) == 48);
+OFP_ASSERT(sizeof(struct ofp11_flow_mod) == 40);
/* Group types. Values in the range [128, 255] are reserved for experimental
* use. */
/* Queue configuration for a given port. */
struct ofp11_queue_get_config_reply {
- struct ofp_header header;
ovs_be32 port;
uint8_t pad[4];
/* struct ofp_packet_queue queues[0]; List of configured queues. */
};
-OFP_ASSERT(sizeof(struct ofp11_queue_get_config_reply) == 16);
+OFP_ASSERT(sizeof(struct ofp11_queue_get_config_reply) == 8);
struct ofp11_stats_msg {
struct ofp_header header;
};
OFP_ASSERT(sizeof(struct ofp11_stats_msg) == 16);
+/* Vendor extension stats message. */
+struct ofp11_vendor_stats_msg {
+ struct ofp11_stats_msg osm; /* Type OFPST_VENDOR. */
+ ovs_be32 vendor; /* Vendor ID:
+ * - MSB 0: low-order bytes are IEEE OUI.
+ * - MSB != 0: defined by OpenFlow
+ * consortium. */
+ /* Followed by vendor-defined arbitrary additional data. */
+};
+OFP_ASSERT(sizeof(struct ofp11_vendor_stats_msg) == 20);
+
/* Stats request of type OFPST_FLOW. */
struct ofp11_flow_stats_request {
- struct ofp11_stats_msg osm;
uint8_t table_id; /* ID of table to read (from ofp_table_stats),
0xff for all tables. */
uint8_t pad[3]; /* Align to 64 bits. */
no restriction. */
struct ofp11_match match; /* Fields to match. */
};
-OFP_ASSERT(sizeof(struct ofp11_flow_stats_request) == 136);
+OFP_ASSERT(sizeof(struct ofp11_flow_stats_request) == 120);
/* Body of reply to OFPST_FLOW request. */
struct ofp11_flow_stats {
/* Body of reply to OFPST_TABLE request. */
struct ofp11_table_stats {
- struct ofp11_stats_msg osm;
uint8_t table_id; /* Identifier of table. Lower numbered tables
are consulted first. */
uint8_t pad[7]; /* Align to 64-bits. */
ovs_be64 lookup_count; /* Number of packets looked up in table. */
ovs_be64 matched_count; /* Number of packets that hit table. */
};
-OFP_ASSERT(sizeof(struct ofp11_table_stats) == 104);
+OFP_ASSERT(sizeof(struct ofp11_table_stats) == 88);
/* Body for ofp_stats_request of type OFPST_PORT. */
struct ofp11_port_stats_request {
- struct ofp11_stats_msg osm;
ovs_be32 port_no; /* OFPST_PORT message must request statistics
* either for a single port (specified in
* port_no) or for all ports (if port_no ==
* OFPP_ANY). */
uint8_t pad[4];
};
-OFP_ASSERT(sizeof(struct ofp11_port_stats_request) == 24);
+OFP_ASSERT(sizeof(struct ofp11_port_stats_request) == 8);
/* Body of reply to OFPST_PORT request. If a counter is unsupported, set
* the field to all ones. */
struct ofp11_port_stats {
- struct ofp11_stats_msg osm;
ovs_be32 port_no;
uint8_t pad[4]; /* Align to 64-bits. */
ovs_be64 rx_packets; /* Number of received packets. */
ovs_be64 rx_crc_err; /* Number of CRC errors. */
ovs_be64 collisions; /* Number of collisions. */
};
-OFP_ASSERT(sizeof(struct ofp11_port_stats) == 120);
+OFP_ASSERT(sizeof(struct ofp11_port_stats) == 104);
struct ofp11_queue_stats_request {
- struct ofp11_stats_msg osm;
ovs_be32 port_no; /* All ports if OFPP_ANY. */
ovs_be32 queue_id; /* All queues if OFPQ_ALL. */
};
-OFP_ASSERT(sizeof(struct ofp11_queue_stats_request) == 24);
+OFP_ASSERT(sizeof(struct ofp11_queue_stats_request) == 8);
struct ofp11_queue_stats {
- struct ofp11_stats_msg osm;
ovs_be32 port_no;
ovs_be32 queue_id; /* Queue id. */
ovs_be64 tx_bytes; /* Number of transmitted bytes. */
ovs_be64 tx_packets; /* Number of transmitted packets. */
ovs_be64 tx_errors; /* # of packets dropped due to overrun. */
};
-OFP_ASSERT(sizeof(struct ofp11_queue_stats) == 48);
+OFP_ASSERT(sizeof(struct ofp11_queue_stats) == 32);
struct ofp11_group_stats_request {
- struct ofp11_stats_msg osm;
ovs_be32 group_id; /* All groups if OFPG_ALL. */
uint8_t pad[4]; /* Align to 64 bits. */
};
-OFP_ASSERT(sizeof(struct ofp11_group_stats_request) == 24);
+OFP_ASSERT(sizeof(struct ofp11_group_stats_request) == 8);
/* Body of reply to OFPST11_GROUP request */
struct ofp11_group_stats {
/* Used in group stats replies. */
struct ofp11_bucket_counter {
- struct ofp11_stats_msg osm;
ovs_be64 packet_count; /* Number of packets processed by bucket. */
ovs_be64 byte_count; /* Number of bytes processed by bucket. */
};
-OFP_ASSERT(sizeof(struct ofp11_bucket_counter) == 32);
+OFP_ASSERT(sizeof(struct ofp11_bucket_counter) == 16);
/* Body of reply to OFPST11_GROUP_DESC request. */
struct ofp11_group_desc_stats {
/* Send packet (controller -> datapath). */
struct ofp11_packet_out {
- struct ofp_header header;
ovs_be32 buffer_id; /* ID assigned by datapath (-1 if none). */
ovs_be32 in_port; /* Packet's input port or OFPP_CONTROLLER. */
ovs_be16 actions_len; /* Size of action array in bytes. */
from the length field in the header.
(Only meaningful if buffer_id == -1.) */
};
-OFP_ASSERT(sizeof(struct ofp11_packet_out) == 24);
+OFP_ASSERT(sizeof(struct ofp11_packet_out) == 16);
/* Packet received on port (datapath -> controller). */
struct ofp11_packet_in {
- struct ofp_header header;
ovs_be32 buffer_id; /* ID assigned by datapath. */
ovs_be32 in_port; /* Port on which frame was received. */
ovs_be32 in_phy_port; /* Physical Port on which frame was received. */
offsetof(struct ofp_packet_in, data) ==
sizeof(struct ofp_packet_in) - 2. */
};
-OFP_ASSERT(sizeof(struct ofp11_packet_in) == 24);
+OFP_ASSERT(sizeof(struct ofp11_packet_in) == 16);
/* Flow removed (datapath -> controller). */
struct ofp11_flow_removed {
- struct ofp_header header;
ovs_be64 cookie; /* Opaque controller-issued identifier. */
ovs_be16 priority; /* Priority level of flow entry. */
ovs_be64 byte_count;
struct ofp11_match match; /* Description of fields. */
};
-OFP_ASSERT(sizeof(struct ofp11_flow_removed) == 136);
+OFP_ASSERT(sizeof(struct ofp11_flow_removed) == 128);
#endif /* openflow/openflow-1.1.h */
#include "openflow/openflow-1.1.h"
-/* OpenFlow 1.2 specific message types, in addition to the common message
- * types. */
-enum ofp12_type {
- /* Controller role change request messages. */
- OFPT12_ROLE_REQUEST = 24, /* Controller/switch message */
- OFPT12_ROLE_REPLY, /* Controller/switch message */
-};
-
/*
* OXM Class IDs.
* The high order bit differentiate reserved classes from member classes.
/* Body of reply to OFPST_TABLE request. */
struct ofp12_table_stats {
- struct ofp11_stats_msg osm;
uint8_t table_id; /* Identifier of table. Lower numbered tables
are consulted first. */
uint8_t pad[7]; /* Align to 64-bits. */
ovs_be64 lookup_count; /* Number of packets looked up in table. */
ovs_be64 matched_count; /* Number of packets that hit table. */
};
-OFP_ASSERT(sizeof(struct ofp12_table_stats) == 144);
+OFP_ASSERT(sizeof(struct ofp12_table_stats) == 128);
/* Body of reply to OFPST12_GROUP_FEATURES request. Group features. */
struct ofp12_group_features_stats {
- struct ofp11_stats_msg osm;
ovs_be32 types; /* Bitmap of OFPGT_* values supported. */
ovs_be32 capabilities; /* Bitmap of OFPGFC12_* capability supported. */
ovs_be32 max_groups[4]; /* Maximum number of groups for each type. */
ovs_be32 actions[4]; /* Bitmaps of OFPAT_* that are supported. */
};
-OFP_ASSERT(sizeof(struct ofp12_group_features_stats) == 56);
+OFP_ASSERT(sizeof(struct ofp12_group_features_stats) == 40);
/* Group configuration flags */
enum ofp12_group_capabilities {
/* Role request and reply message. */
struct ofp12_role_request {
- struct ofp_header header; /* Type OFPT12_ROLE_REQUEST/OFPT12_ROLE_REPLY. */
ovs_be32 role; /* One of OFPCR12_ROLE_*. */
uint8_t pad[4]; /* Align to 64 bits. */
ovs_be64 generation_id; /* Master Election Generation Id */
};
-OFP_ASSERT(sizeof(struct ofp12_role_request) == 24);
+OFP_ASSERT(sizeof(struct ofp12_role_request) == 16);
/* Controller roles. */
enum ofp12_controller_role {
/* Packet received on port (datapath -> controller). */
struct ofp12_packet_in {
- struct ofp_header header;
ovs_be32 buffer_id; /* ID assigned by datapath. */
ovs_be16 total_len; /* Full length of frame. */
uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */
/* uint8_t pad[2]; Align to 64 bit + 16 bit */
/* uint8_t data[0]; Ethernet frame */
};
-OFP_ASSERT(sizeof(struct ofp12_packet_in) == 16);
+OFP_ASSERT(sizeof(struct ofp12_packet_in) == 8);
/* Flow removed (datapath -> controller). */
struct ofp12_flow_removed {
- struct ofp_header header;
ovs_be64 cookie; /* Opaque controller-issued identifier. */
ovs_be16 priority; /* Priority level of flow entry. */
ovs_be64 byte_count;
/* struct ofp12_match match; Description of fields. Variable size. */
};
-OFP_ASSERT(sizeof(struct ofp12_flow_removed) == 48);
+OFP_ASSERT(sizeof(struct ofp12_flow_removed) == 40);
#endif /* openflow/openflow-1.2.h */
#define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */
-/* Common OpenFlow message types. */
-enum ofp_type {
- /* Immutable messages. */
- OFPT_HELLO, /* Symmetric message */
- OFPT_ERROR, /* Symmetric message */
- OFPT_ECHO_REQUEST, /* Symmetric message */
- OFPT_ECHO_REPLY, /* Symmetric message */
- OFPT_VENDOR, /* Symmetric message */
-
- /* Switch configuration messages. */
- OFPT_FEATURES_REQUEST, /* Controller/switch message */
- OFPT_FEATURES_REPLY, /* Controller/switch message */
- OFPT_GET_CONFIG_REQUEST, /* Controller/switch message */
- OFPT_GET_CONFIG_REPLY, /* Controller/switch message */
- OFPT_SET_CONFIG, /* Controller/switch message */
-
- /* Asynchronous messages. */
- OFPT_PACKET_IN, /* Async message */
- OFPT_FLOW_REMOVED, /* Async message */
- OFPT_PORT_STATUS, /* Async message */
-
- /* Controller command messages. */
- OFPT_PACKET_OUT, /* Controller/switch message */
- OFPT_FLOW_MOD, /* Controller/switch message */
-};
-
/* Header on all OpenFlow packets. */
struct ofp_header {
uint8_t version; /* An OpenFlow version number, e.g. OFP10_VERSION. */
/* Switch features. */
struct ofp_switch_features {
- struct ofp_header header;
ovs_be64 datapath_id; /* Datapath unique ID. The lower 48-bits are for
a MAC address, while the upper 16-bits are
implementer-defined. */
/* Followed by an array of struct ofp10_phy_port or struct ofp11_port
* structures. The number is inferred from header.length. */
};
-OFP_ASSERT(sizeof(struct ofp_switch_features) == 32);
+OFP_ASSERT(sizeof(struct ofp_switch_features) == 24);
/* Common capabilities supported by the datapath (struct ofp_switch_features,
* member capabilities). */
/* A physical port has changed in the datapath */
struct ofp_port_status {
- struct ofp_header header;
uint8_t reason; /* One of OFPPR_*. */
uint8_t pad[7]; /* Align to 64-bits. */
/* Followed by struct ofp10_phy_port or struct ofp11_port. */
};
-OFP_ASSERT(sizeof(struct ofp_port_status) == 16);
-
-enum ofp_stats_types {
- /* Description of this OpenFlow switch. (OFPMP_DESC)
- * The OF1.0 request is struct ofp_stats_msg.
- * The OF1.0 reply is struct ofp_desc_stats. */
- OFPST_DESC = 0,
-
- /* Individual flow statistics. (OFPMP_FLOW)
- * The OF1.0 request is struct ofp_flow_stats_request.
- * The OF1.0 reply body is an array of struct ofp_flow_stats. */
- OFPST_FLOW = 1,
-
- /* Aggregate flow statistics. (OFPMP_AGGREGATE)
- * The OF1.0 request is struct ofp_flow_stats_request.
- * The OF1.0 reply is struct ofp_aggregate_stats_reply. */
- OFPST_AGGREGATE = 2,
-
- /* Flow table statistics. (OFPMP_TABLE)
- * The OF1.0 request is struct ofp_stats_msg.
- * The OF1.0 reply body is an array of struct ofp_table_stats. */
- OFPST_TABLE = 3,
-
- /* Physical port statistics. (OFPMP_PORT_STATS)
- * The OF1.0 request is struct ofp_port_stats_request.
- * The OF1.0 reply body is an array of struct ofp_port_stats. */
- OFPST_PORT = 4,
-
- /* Queue statistics for a port. (OFPMP_QUEUE)
- * The OF1.0 request is struct ofp_stats_msg.
- * The OF1.0 reply body is an array of struct ofp_queue_stats. */
- OFPST_QUEUE = 5,
-
- /* Port description. (OFPMP_PORT_DESC)
- * This was introduced as part of OF1.3, but is useful for bridges
- * with many ports, so we support it with OF1.0, too.
- * The OF1.0 request is struct ofp_stats_msg.
- * The OF1.0 reply body is an array of struct ofp10_phy_port. */
- OFPST_PORT_DESC = 13,
-
- /* Vendor extension.
- * The OF1.0 request and reply begin with struct ofp_vendor_stats. */
- OFPST_VENDOR = 0xffff
-};
+OFP_ASSERT(sizeof(struct ofp_port_status) == 8);
/* The match type indicates the match structure (set of fields that compose the
* match) in use. The match type is placed in the type field at the beginning
/dirs.c
/coverage-counters.c
/ofp-errors.inc
+/ofp-msgs.inc
/vswitch-idl.c
/vswitch-idl.h
/vswitch-idl.ovsidl
lib/ofp-actions.h \
lib/ofp-errors.c \
lib/ofp-errors.h \
+ lib/ofp-msgs.c \
+ lib/ofp-msgs.h \
lib/ofp-parse.c \
lib/ofp-parse.h \
lib/ofp-print.c \
$(srcdir)/lib/ofp-errors.c: $(srcdir)/lib/ofp-errors.inc
EXTRA_DIST += build-aux/extract-ofp-errors lib/ofp-errors.inc
+$(srcdir)/lib/ofp-msgs.inc: \
+ lib/ofp-msgs.h $(srcdir)/build-aux/extract-ofp-msgs
+ $(run_python) $(srcdir)/build-aux/extract-ofp-msgs \
+ $(srcdir)/lib/ofp-msgs.h $@ > $@.tmp && mv $@.tmp $@
+$(srcdir)/lib/ofp-msgs.c: $(srcdir)/lib/ofp-msgs.inc
+EXTRA_DIST += build-aux/extract-ofp-msgs lib/ofp-msgs.inc
+
INSTALL_DATA_LOCAL += lib-install-data-local
lib-install-data-local:
$(MKDIR_P) $(DESTDIR)$(RUNDIR)
#include "ofpbuf.h"
#include "ofp-actions.h"
#include "ofp-errors.h"
+#include "ofp-msgs.h"
#include "ofp-parse.h"
#include "ofp-print.h"
#include "ofp-util.h"
static void send_features_request(struct lswitch *, struct rconn *);
static enum ofperr process_switch_features(struct lswitch *,
- struct ofp_switch_features *);
+ struct ofp_header *);
static void process_packet_in(struct lswitch *, struct rconn *,
const struct ofp_header *);
static void process_echo_request(struct lswitch *, struct rconn *,
lswitch_process_packet(struct lswitch *sw, struct rconn *rconn,
const struct ofpbuf *msg)
{
- const struct ofp_header *oh = msg->data;
- const struct ofputil_msg_type *type;
+ enum ofptype type;
+ struct ofpbuf b;
+
+ b = *msg;
+ if (ofptype_pull(&type, &b)) {
+ return;
+ }
if (sw->datapath_id == 0
- && oh->type != OFPT_ECHO_REQUEST
- && oh->type != OFPT_FEATURES_REPLY) {
+ && type != OFPTYPE_ECHO_REQUEST
+ && type != OFPTYPE_FEATURES_REPLY) {
send_features_request(sw, rconn);
return;
}
- ofputil_decode_msg_type(oh, &type);
- switch (ofputil_msg_type_code(type)) {
- case OFPUTIL_OFPT_ECHO_REQUEST:
+ switch (type) {
+ case OFPTYPE_ECHO_REQUEST:
process_echo_request(sw, rconn, msg->data);
break;
- case OFPUTIL_OFPT_FEATURES_REPLY:
+ case OFPTYPE_FEATURES_REPLY:
process_switch_features(sw, msg->data);
break;
- case OFPUTIL_OFPT_PACKET_IN:
- case OFPUTIL_NXT_PACKET_IN:
+ case OFPTYPE_PACKET_IN:
process_packet_in(sw, rconn, msg->data);
break;
- case OFPUTIL_OFPT_FLOW_REMOVED:
+ case OFPTYPE_FLOW_REMOVED:
/* Nothing to do. */
break;
- case OFPUTIL_MSG_INVALID:
- case OFPUTIL_OFPT_HELLO:
- case OFPUTIL_OFPT_ERROR:
- case OFPUTIL_OFPT_ECHO_REPLY:
- case OFPUTIL_OFPT_FEATURES_REQUEST:
- case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
- case OFPUTIL_OFPT_GET_CONFIG_REPLY:
- case OFPUTIL_OFPT_SET_CONFIG:
- case OFPUTIL_OFPT_PORT_STATUS:
- case OFPUTIL_OFPT_PACKET_OUT:
- case OFPUTIL_OFPT_FLOW_MOD:
- case OFPUTIL_OFPT_PORT_MOD:
- case OFPUTIL_OFPT_BARRIER_REQUEST:
- case OFPUTIL_OFPT_BARRIER_REPLY:
- case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
- case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
- case OFPUTIL_OFPST_DESC_REQUEST:
- case OFPUTIL_OFPST_FLOW_REQUEST:
- case OFPUTIL_OFPST_AGGREGATE_REQUEST:
- case OFPUTIL_OFPST_TABLE_REQUEST:
- case OFPUTIL_OFPST_PORT_REQUEST:
- case OFPUTIL_OFPST_QUEUE_REQUEST:
- case OFPUTIL_OFPST_PORT_DESC_REQUEST:
- case OFPUTIL_OFPST_DESC_REPLY:
- case OFPUTIL_OFPST_FLOW_REPLY:
- case OFPUTIL_OFPST_QUEUE_REPLY:
- case OFPUTIL_OFPST_PORT_REPLY:
- case OFPUTIL_OFPST_TABLE_REPLY:
- case OFPUTIL_OFPST_AGGREGATE_REPLY:
- case OFPUTIL_OFPST_PORT_DESC_REPLY:
- case OFPUTIL_NXT_ROLE_REQUEST:
- case OFPUTIL_NXT_ROLE_REPLY:
- case OFPUTIL_NXT_FLOW_MOD_TABLE_ID:
- case OFPUTIL_NXT_SET_FLOW_FORMAT:
- case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
- case OFPUTIL_NXT_FLOW_MOD:
- case OFPUTIL_NXT_FLOW_REMOVED:
- case OFPUTIL_NXT_FLOW_AGE:
- case OFPUTIL_NXT_FLOW_MONITOR_CANCEL:
- case OFPUTIL_NXT_FLOW_MONITOR_PAUSED:
- case OFPUTIL_NXT_FLOW_MONITOR_RESUMED:
- case OFPUTIL_NXT_SET_ASYNC_CONFIG:
- case OFPUTIL_NXT_SET_CONTROLLER_ID:
- case OFPUTIL_NXST_FLOW_REQUEST:
- case OFPUTIL_NXST_AGGREGATE_REQUEST:
- case OFPUTIL_NXST_FLOW_MONITOR_REQUEST:
- case OFPUTIL_NXST_FLOW_REPLY:
- case OFPUTIL_NXST_AGGREGATE_REPLY:
- case OFPUTIL_NXST_FLOW_MONITOR_REPLY:
+ case OFPTYPE_HELLO:
+ case OFPTYPE_ERROR:
+ case OFPTYPE_ECHO_REPLY:
+ case OFPTYPE_FEATURES_REQUEST:
+ case OFPTYPE_GET_CONFIG_REQUEST:
+ case OFPTYPE_GET_CONFIG_REPLY:
+ case OFPTYPE_SET_CONFIG:
+ case OFPTYPE_PORT_STATUS:
+ case OFPTYPE_PACKET_OUT:
+ case OFPTYPE_FLOW_MOD:
+ case OFPTYPE_PORT_MOD:
+ case OFPTYPE_BARRIER_REQUEST:
+ case OFPTYPE_BARRIER_REPLY:
+ case OFPTYPE_DESC_STATS_REQUEST:
+ case OFPTYPE_DESC_STATS_REPLY:
+ case OFPTYPE_FLOW_STATS_REQUEST:
+ case OFPTYPE_FLOW_STATS_REPLY:
+ case OFPTYPE_AGGREGATE_STATS_REQUEST:
+ case OFPTYPE_AGGREGATE_STATS_REPLY:
+ case OFPTYPE_TABLE_STATS_REQUEST:
+ case OFPTYPE_TABLE_STATS_REPLY:
+ case OFPTYPE_PORT_STATS_REQUEST:
+ case OFPTYPE_PORT_STATS_REPLY:
+ case OFPTYPE_QUEUE_STATS_REQUEST:
+ case OFPTYPE_QUEUE_STATS_REPLY:
+ case OFPTYPE_PORT_DESC_STATS_REQUEST:
+ case OFPTYPE_PORT_DESC_STATS_REPLY:
+ case OFPTYPE_ROLE_REQUEST:
+ case OFPTYPE_ROLE_REPLY:
+ case OFPTYPE_SET_FLOW_FORMAT:
+ case OFPTYPE_FLOW_MOD_TABLE_ID:
+ case OFPTYPE_SET_PACKET_IN_FORMAT:
+ case OFPTYPE_FLOW_AGE:
+ case OFPTYPE_SET_ASYNC_CONFIG:
+ case OFPTYPE_SET_CONTROLLER_ID:
+ case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
+ case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
+ case OFPTYPE_FLOW_MONITOR_CANCEL:
+ case OFPTYPE_FLOW_MONITOR_PAUSED:
+ case OFPTYPE_FLOW_MONITOR_RESUMED:
default:
if (VLOG_IS_DBG_ENABLED()) {
char *s = ofp_to_string(msg->data, msg->size, 2);
struct ofp_switch_config *osc;
/* Send OFPT_FEATURES_REQUEST. */
- make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &b);
+ b = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, OFP10_VERSION, 0);
queue_tx(sw, rconn, b);
/* Send OFPT_SET_CONFIG. */
- osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &b);
+ b = ofpraw_alloc(OFPRAW_OFPT_SET_CONFIG, OFP10_VERSION, sizeof *osc);
+ osc = ofpbuf_put_uninit(b, sizeof *osc);
osc->miss_send_len = htons(OFP_DEFAULT_MISS_SEND_LEN);
queue_tx(sw, rconn, b);
}
static enum ofperr
-process_switch_features(struct lswitch *sw, struct ofp_switch_features *osf)
+process_switch_features(struct lswitch *sw, struct ofp_header *oh)
{
struct ofputil_switch_features features;
struct ofputil_phy_port port;
enum ofperr error;
struct ofpbuf b;
- error = ofputil_decode_switch_features(osf, &features, &b);
+ error = ofputil_decode_switch_features(oh, &features, &b);
if (error) {
VLOG_ERR("received invalid switch feature reply (%s)",
ofperr_to_string(error));
sw->datapath_id = features.datapath_id;
- while (!ofputil_pull_phy_port(osf->header.version, &b, &port)) {
+ while (!ofputil_pull_phy_port(oh->version, &b, &port)) {
struct lswitch_port *lp = shash_find_data(&sw->queue_names, port.name);
if (lp && hmap_node_is_null(&lp->hmap_node)) {
lp->port_no = port.port_no;
#include <errno.h>
#include "byte-order.h"
#include "dynamic-string.h"
+#include "ofp-msgs.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
pair = ofperr_get_pair__(error, domain);
if (!ofperr_is_nx_extension(error)) {
- oem = make_openflow_xid(data_len + sizeof *oem, OFPT_ERROR, xid, &buf);
+ buf = ofpraw_alloc_xid(OFPRAW_OFPT_ERROR, domain->version, xid,
+ sizeof *oem + data_len);
+
+ oem = ofpbuf_put_uninit(buf, sizeof *oem);
oem->type = htons(pair->type);
oem->code = htons(pair->code);
} else {
struct nx_vendor_error *nve;
- oem = make_openflow_xid(data_len + sizeof *oem + sizeof *nve,
- OFPT_ERROR, xid, &buf);
+ buf = ofpraw_alloc_xid(OFPRAW_OFPT_ERROR, domain->version, xid,
+ sizeof *oem + sizeof *nve + data_len);
+
+ oem = ofpbuf_put_uninit(buf, sizeof *oem);
oem->type = htons(NXET_VENDOR);
oem->code = htons(NXVC_VENDOR_ERROR);
- nve = (struct nx_vendor_error *) oem->data;
+ nve = ofpbuf_put_uninit(buf, sizeof *nve);
nve->vendor = htonl(NX_VENDOR_ID);
nve->type = htons(pair->type);
nve->code = htons(pair->code);
}
- oem->header.version = domain->version;
- buf->size -= data_len;
ofpbuf_put(buf, data, data_len);
return buf;
/* Tries to decodes 'oh', which should be an OpenFlow OFPT_ERROR message.
* Returns an OFPERR_* constant on success, 0 on failure.
*
- * If 'payload_ofs' is nonnull, on success '*payload_ofs' is set to the offset
- * to the payload starting from 'oh' and on failure it is set to 0. */
+ * If 'payload' is nonnull, on success '*payload' is initialized to the
+ * error's payload, and on failure it is cleared. */
enum ofperr
-ofperr_decode_msg(const struct ofp_header *oh, size_t *payload_ofs)
+ofperr_decode_msg(const struct ofp_header *oh, struct ofpbuf *payload)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
const struct ofperr_domain *domain;
const struct ofp_error_msg *oem;
+ enum ofpraw raw;
uint16_t type, code;
enum ofperr error;
struct ofpbuf b;
- if (payload_ofs) {
- *payload_ofs = 0;
+ if (payload) {
+ memset(payload, 0, sizeof *payload);
}
/* Pull off the error message. */
ofpbuf_use_const(&b, oh, ntohs(oh->length));
- oem = ofpbuf_try_pull(&b, sizeof *oem);
- if (!oem) {
+ error = ofpraw_pull(&raw, &b);
+ if (error) {
return 0;
}
+ oem = ofpbuf_pull(&b, sizeof *oem);
- /* Check message type and version. */
- if (oh->type != OFPT_ERROR) {
- return 0;
- }
+ /* Check version. */
domain = ofperr_domain_from_version(oh->version);
if (!domain) {
return 0;
if (!error) {
error = ofperr_decode_type(domain, type);
}
- if (error && payload_ofs) {
- *payload_ofs = (uint8_t *) b.data - (uint8_t *) oh;
+ if (error && payload) {
+ ofpbuf_use_const(payload, b.data, b.size);
}
return error;
}
struct ds;
struct ofp_header;
+struct ofpbuf;
/* Error codes.
*
enum ofperr ofperr_decode_type(const struct ofperr_domain *, uint16_t type);
enum ofperr ofperr_from_name(const char *);
-enum ofperr ofperr_decode_msg(const struct ofp_header *, size_t *payload_ofs);
+enum ofperr ofperr_decode_msg(const struct ofp_header *,
+ struct ofpbuf *payload);
struct ofpbuf *ofperr_encode_reply(enum ofperr, const struct ofp_header *);
struct ofpbuf *ofperr_encode_hello(enum ofperr, const struct ofperr_domain *,
const char *);
--- /dev/null
+/*
+ * Copyright (c) 2012 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "ofp-msgs.h"
+#include <assert.h>
+#include "byte-order.h"
+#include "dynamic-string.h"
+#include "hash.h"
+#include "hmap.h"
+#include "ofpbuf.h"
+#include "openflow/nicira-ext.h"
+#include "openflow/openflow.h"
+#include "vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(ofp_msgs);
+
+#define OFPT_VENDOR 4
+#define OFPT10_STATS_REQUEST 16
+#define OFPT10_STATS_REPLY 17
+#define OFPT11_STATS_REQUEST 18
+#define OFPT11_STATS_REPLY 19
+#define OFPST_VENDOR 0xffff
+
+/* A thin abstraction of OpenFlow headers:
+ *
+ * - 'version' and 'type' come straight from struct ofp_header, so these are
+ * always present and meaningful.
+ *
+ * - 'stat' comes from the 'type' member in statistics messages only. It is
+ * meaningful, therefore, only if 'version' and 'type' taken together
+ * specify a statistics request or reply. Otherwise it is 0.
+ *
+ * - 'vendor' is meaningful only for vendor messages, that is, if 'version'
+ * and 'type' specify a vendor message or if 'version' and 'type' specify
+ * a statistics message and 'stat' specifies a vendor statistic type.
+ * Otherwise it is 0.
+ *
+ * - 'subtype' is meaningful only for vendor messages and otherwise 0. It
+ * specifies a vendor-defined subtype. There is no standard format for
+ * these but 32 bits seems like it should be enough. */
+struct ofphdrs {
+ uint8_t version; /* From ofp_header. */
+ uint8_t type; /* From ofp_header. */
+ uint16_t stat; /* From ofp10_stats_msg or ofp11_stats_msg. */
+ uint32_t vendor; /* From ofp_vendor_header,
+ * ofp10_vendor_stats_msg, or
+ * ofp11_vendor_stats_msg. */
+ uint32_t subtype; /* From nicira_header, nicira10_stats_msg, or
+ * nicira11_stats_msg. */
+};
+BUILD_ASSERT_DECL(sizeof(struct ofphdrs) == 12);
+
+/* A mapping from OpenFlow headers to OFPRAW_*. */
+struct raw_instance {
+ struct hmap_node hmap_node; /* In 'raw_instance_map'. */
+ struct ofphdrs hdrs; /* Key. */
+ enum ofpraw raw; /* Value. */
+ unsigned int hdrs_len; /* ofphdrs_len(hdrs). */
+};
+
+/* Information about a particular 'enum ofpraw'. */
+struct raw_info {
+ /* All possible instantiations of this OFPRAW_* into OpenFlow headers. */
+ struct raw_instance *instances; /* min_version - max_version + 1 elems. */
+ uint8_t min_version;
+ uint8_t max_version;
+
+ unsigned int min_body;
+ unsigned int extra_multiple;
+ enum ofptype type;
+ const char *name;
+};
+
+/* All understood OpenFlow message types, indexed by their 'struct ofphdrs'. */
+static struct hmap raw_instance_map;
+#include "ofp-msgs.inc"
+
+static ovs_be32 alloc_xid(void);
+
+/* ofphdrs functions. */
+static uint32_t ofphdrs_hash(const struct ofphdrs *);
+static bool ofphdrs_equal(const struct ofphdrs *a, const struct ofphdrs *b);
+static enum ofperr ofphdrs_decode(struct ofphdrs *,
+ const struct ofp_header *oh, size_t length);
+static void ofphdrs_decode_assert(struct ofphdrs *,
+ const struct ofp_header *oh, size_t length);
+size_t ofphdrs_len(const struct ofphdrs *);
+
+static const struct raw_info *raw_info_get(enum ofpraw);
+static struct raw_instance *raw_instance_get(const struct raw_info *,
+ uint8_t version);
+
+static enum ofperr ofpraw_from_ofphdrs(enum ofpraw *, const struct ofphdrs *);
+\f
+/* Returns a transaction ID to use for an outgoing OpenFlow message. */
+static ovs_be32
+alloc_xid(void)
+{
+ static uint32_t next_xid = 1;
+ return htonl(next_xid++);
+}
+\f
+static uint32_t
+ofphdrs_hash(const struct ofphdrs *hdrs)
+{
+ BUILD_ASSERT_DECL(sizeof *hdrs == 12);
+ return hash_words((const uint32_t *) hdrs, 3, 0);
+}
+
+static bool
+ofphdrs_equal(const struct ofphdrs *a, const struct ofphdrs *b)
+{
+ return !memcmp(a, b, sizeof *a);
+}
+
+static void
+log_bad_vendor(uint32_t vendor)
+{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+
+ VLOG_WARN_RL(&rl, "OpenFlow message has unknown vendor %#"PRIx32, vendor);
+}
+
+static enum ofperr
+ofphdrs_decode(struct ofphdrs *hdrs,
+ const struct ofp_header *oh, size_t length)
+{
+ memset(hdrs, 0, sizeof *hdrs);
+ if (length < sizeof *oh) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ /* Get base message version and type (OFPT_*). */
+ hdrs->version = oh->version;
+ hdrs->type = oh->type;
+
+ if (hdrs->type == OFPT_VENDOR) {
+ /* Get vendor. */
+ const struct ofp_vendor_header *ovh;
+
+ if (length < sizeof *ovh) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ ovh = (const struct ofp_vendor_header *) oh;
+ hdrs->vendor = ntohl(ovh->vendor);
+ if (hdrs->vendor == NX_VENDOR_ID) {
+ /* Get Nicira message subtype (NXT_*). */
+ const struct nicira_header *nh;
+
+ if (length < sizeof *nh) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ nh = (const struct nicira_header *) oh;
+ hdrs->subtype = ntohl(nh->subtype);
+ } else {
+ log_bad_vendor(hdrs->vendor);
+ return OFPERR_OFPBRC_BAD_VENDOR;
+ }
+ } else if (hdrs->version == OFP10_VERSION
+ && (hdrs->type == OFPT10_STATS_REQUEST ||
+ hdrs->type == OFPT10_STATS_REPLY)) {
+ const struct ofp_stats_msg *osm;
+
+ /* Get statistic type (OFPST_*). */
+ if (length < sizeof *osm) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ osm = (const struct ofp_stats_msg *) oh;
+ hdrs->stat = ntohs(osm->type);
+
+ if (hdrs->stat == OFPST_VENDOR) {
+ /* Get vendor. */
+ const struct ofp10_vendor_stats_msg *ovsm;
+
+ if (length < sizeof *ovsm) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ ovsm = (const struct ofp10_vendor_stats_msg *) oh;
+ hdrs->vendor = ntohl(ovsm->vendor);
+ if (hdrs->vendor == NX_VENDOR_ID) {
+ /* Get Nicira statistic type (NXST_*). */
+ const struct nicira10_stats_msg *nsm;
+
+ if (length < sizeof *nsm) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ nsm = (const struct nicira10_stats_msg *) oh;
+ hdrs->subtype = ntohl(nsm->subtype);
+ } else {
+ log_bad_vendor(hdrs->vendor);
+ return OFPERR_OFPBRC_BAD_VENDOR;
+ }
+ }
+ } else if (hdrs->version != OFP10_VERSION
+ && (hdrs->type == OFPT11_STATS_REQUEST ||
+ hdrs->type == OFPT11_STATS_REPLY)) {
+ const struct ofp11_stats_msg *osm;
+
+ /* Get statistic type (OFPST_*). */
+ if (length < sizeof *osm) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ osm = (const struct ofp11_stats_msg *) oh;
+ hdrs->stat = ntohs(osm->type);
+
+ if (hdrs->stat == OFPST_VENDOR) {
+ /* Get vendor. */
+ const struct ofp11_vendor_stats_msg *ovsm;
+
+ if (length < sizeof *ovsm) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ ovsm = (const struct ofp11_vendor_stats_msg *) oh;
+ hdrs->vendor = ntohl(ovsm->vendor);
+ if (hdrs->vendor == NX_VENDOR_ID) {
+ /* Get Nicira statistic type (NXST_*). */
+ const struct nicira11_stats_msg *nsm;
+
+ if (length < sizeof *nsm) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ nsm = (const struct nicira11_stats_msg *) oh;
+ hdrs->subtype = ntohl(nsm->subtype);
+ } else {
+ log_bad_vendor(hdrs->vendor);
+ return OFPERR_OFPBRC_BAD_VENDOR;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void
+ofphdrs_decode_assert(struct ofphdrs *hdrs,
+ const struct ofp_header *oh, size_t length)
+{
+ enum ofperr error = ofphdrs_decode(hdrs, oh, length);
+ assert(!error);
+}
+
+static bool
+ofphdrs_is_stat(const struct ofphdrs *hdrs)
+{
+ return (hdrs->version == OFP10_VERSION
+ ? (hdrs->type == OFPT10_STATS_REQUEST ||
+ hdrs->type == OFPT10_STATS_REPLY)
+ : (hdrs->type == OFPT11_STATS_REQUEST ||
+ hdrs->type == OFPT11_STATS_REPLY));
+}
+
+size_t
+ofphdrs_len(const struct ofphdrs *hdrs)
+{
+ if (hdrs->type == OFPT_VENDOR) {
+ return sizeof(struct nicira_header);
+ }
+
+ if (hdrs->version == OFP10_VERSION) {
+ if (hdrs->type == OFPT10_STATS_REQUEST ||
+ hdrs->type == OFPT10_STATS_REPLY) {
+ return (hdrs->stat == OFPST_VENDOR
+ ? sizeof(struct nicira10_stats_msg)
+ : sizeof(struct ofp_stats_msg));
+ }
+ } else {
+ if (hdrs->type == OFPT11_STATS_REQUEST ||
+ hdrs->type == OFPT11_STATS_REPLY) {
+ return (hdrs->stat == OFPST_VENDOR
+ ? sizeof(struct nicira11_stats_msg)
+ : sizeof(struct ofp11_stats_msg));
+ }
+ }
+
+ return sizeof(struct ofp_header);
+}
+\f
+/* Determines the OFPRAW_* type of the OpenFlow message at 'oh', which has
+ * length 'oh->length'. (The caller must ensure that 'oh->length' bytes of
+ * data are readable at 'oh'.) On success, returns 0 and stores the type into
+ * '*raw'. On failure, returns an OFPERR_* error code and zeros '*raw'.
+ *
+ * This function checks that 'oh' is a valid length for its particular type of
+ * message, and returns an error if not. */
+enum ofperr
+ofpraw_decode(enum ofpraw *raw, const struct ofp_header *oh)
+{
+ struct ofpbuf msg;
+
+ ofpbuf_use_const(&msg, oh, ntohs(oh->length));
+ return ofpraw_pull(raw, &msg);
+}
+
+/* Determines the OFPRAW_* type of the OpenFlow message in 'msg', which starts
+ * at 'msg->data' and has length 'msg->size' bytes. On success, returns 0 and
+ * stores the type into '*rawp'. On failure, returns an OFPERR_* error code
+ * and zeros '*rawp'.
+ *
+ * This function checks that the message has a valid length for its particular
+ * type of message, and returns an error if not.
+ *
+ * In addition to setting '*rawp', this function pulls off the OpenFlow header
+ * (including the stats headers, vendor header, and any subtype header) with
+ * ofpbuf_pull(). It also sets 'msg->l2' to the start of the OpenFlow header
+ * and 'msg->l3' just beyond the headers (that is, to the final value of
+ * msg->data). */
+enum ofperr
+ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg)
+{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+ const struct raw_instance *instance;
+ const struct raw_info *info;
+ struct ofphdrs hdrs;
+
+ unsigned int min_len;
+ unsigned int len;
+
+ enum ofperr error;
+ enum ofpraw raw;
+
+ /* Set default outputs. */
+ msg->l2 = msg->l3 = msg->data;
+ *rawp = 0;
+
+ len = msg->size;
+ error = ofphdrs_decode(&hdrs, msg->data, len);
+ if (error) {
+ return error;
+ }
+
+ error = ofpraw_from_ofphdrs(&raw, &hdrs);
+ if (error) {
+ return error;
+ }
+
+ info = raw_info_get(raw);
+ instance = raw_instance_get(info, hdrs.version);
+ msg->l2 = ofpbuf_pull(msg, instance->hdrs_len);
+ msg->l3 = msg->data;
+
+ min_len = instance->hdrs_len + info->min_body;
+ switch (info->extra_multiple) {
+ case 0:
+ if (len != min_len) {
+ VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected "
+ "length %u)", info->name, len, min_len);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ break;
+
+ case 1:
+ if (len < min_len) {
+ VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected "
+ "length at least %u bytes)",
+ info->name, len, min_len);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ break;
+
+ default:
+ if (len < min_len || (len - min_len) % info->extra_multiple) {
+ VLOG_WARN_RL(&rl, "received %s with incorrect length %u (must be "
+ "exactly %u bytes or longer by an integer multiple "
+ "of %u bytes)",
+ info->name, len, min_len, info->extra_multiple);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ break;
+ }
+
+ *rawp = raw;
+ return 0;
+}
+
+/* Does the same job as ofpraw_pull(), except that it assert-fails if
+ * ofpbuf_pull() would have reported an error. Thus, it's able to use the
+ * return value for the OFPRAW_* message type instead of an error code.
+ *
+ * (It only makes sense to use this function if you previously called
+ * ofpbuf_decode() on the message and thus know that it's OK.) */
+enum ofpraw
+ofpraw_pull_assert(struct ofpbuf *msg)
+{
+ enum ofperr error;
+ enum ofpraw raw;
+
+ error = ofpraw_pull(&raw, msg);
+ assert(!error);
+ return raw;
+}
+
+/* Determines the OFPRAW_* type of the OpenFlow message that starts at 'oh' and
+ * has length 'length' bytes. On success, returns 0 and stores the type into
+ * '*rawp'. On failure, returns an OFPERR_* error code and zeros '*rawp'.
+ *
+ * Unlike other functions for decoding message types, this one is not picky
+ * about message length. For example, it will successfully decode a message
+ * whose body is shorter than the minimum length for a message of its type.
+ * Thus, this is the correct function to use for decoding the type of a message
+ * that might have been truncated, such as the payload of an OpenFlow error
+ * message (which is allowed to be truncated to 64 bytes). */
+enum ofperr
+ofpraw_decode_partial(enum ofpraw *raw,
+ const struct ofp_header *oh, size_t length)
+{
+ struct ofphdrs hdrs;
+ enum ofperr error;
+
+ error = ofphdrs_decode(&hdrs, oh, length);
+ if (!error) {
+ error = ofpraw_from_ofphdrs(raw, &hdrs);
+ }
+
+ if (error) {
+ *raw = 0;
+ }
+ return error;
+}
+\f
+/* Encoding messages using OFPRAW_* values. */
+
+static void ofpraw_put__(enum ofpraw, uint8_t version, ovs_be32 xid,
+ size_t extra_tailroom, struct ofpbuf *);
+
+/* Allocates and returns a new ofpbuf that contains an OpenFlow header for
+ * 'raw' with OpenFlow version 'version' and a fresh OpenFlow transaction ID.
+ * The ofpbuf has enough tailroom for the minimum body length of 'raw', plus
+ * 'extra_tailroom' additional bytes.
+ *
+ * Each 'raw' value is valid only for certain OpenFlow versions. The caller
+ * must specify a valid (raw, version) pair.
+ *
+ * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header
+ * and 'l3' points just after it, to where the message's body will start. The
+ * caller must actually allocate the body into the space reserved for it,
+ * e.g. with ofpbuf_put_uninit().
+ *
+ * The caller owns the returned ofpbuf and must free it when it is no longer
+ * needed, e.g. with ofpbuf_delete(). */
+struct ofpbuf *
+ofpraw_alloc(enum ofpraw raw, uint8_t version, size_t extra_tailroom)
+{
+ return ofpraw_alloc_xid(raw, version, alloc_xid(), extra_tailroom);
+}
+
+/* Same as ofpraw_alloc() but the caller provides the transaction ID. */
+struct ofpbuf *
+ofpraw_alloc_xid(enum ofpraw raw, uint8_t version, ovs_be32 xid,
+ size_t extra_tailroom)
+{
+ struct ofpbuf *buf = ofpbuf_new(0);
+ ofpraw_put__(raw, version, xid, extra_tailroom, buf);
+ return buf;
+}
+
+/* Same as ofpraw_alloc(), but obtains the OpenFlow version and transaction ID
+ * from 'request->version' and 'request->xid', respectively.
+ *
+ * Even though the version comes from 'request->version', the caller must still
+ * know what it is doing, by specifying a valid pairing of 'raw' and
+ * 'request->version', just like ofpraw_alloc(). */
+struct ofpbuf *
+ofpraw_alloc_reply(enum ofpraw raw, const struct ofp_header *request,
+ size_t extra_tailroom)
+{
+ return ofpraw_alloc_xid(raw, request->version, request->xid,
+ extra_tailroom);
+}
+
+/* Allocates and returns a new ofpbuf that contains an OpenFlow header that is
+ * a stats reply to the stats request in 'request', using the same OpenFlow
+ * version and transaction ID as 'request'. The ofpbuf has enough tailroom for
+ * the stats reply's minimum body length, plus 'extra_tailroom' additional
+ * bytes.
+ *
+ * 'request' must be a stats request, that is, an OFPRAW_OFPST* or OFPRAW_NXST*
+ * value. Every stats request has a corresponding reply, so the (raw, version)
+ * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here.
+ *
+ * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header
+ * and 'l3' points just after it, to where the message's body will start. The
+ * caller must actually allocate the body into the space reserved for it,
+ * e.g. with ofpbuf_put_uninit().
+ *
+ * The caller owns the returned ofpbuf and must free it when it is no longer
+ * needed, e.g. with ofpbuf_delete(). */
+struct ofpbuf *
+ofpraw_alloc_stats_reply(const struct ofp_header *request,
+ size_t extra_tailroom)
+{
+ enum ofpraw request_raw;
+ enum ofpraw reply_raw;
+ enum ofperr error;
+
+ error = ofpraw_decode_partial(&request_raw, request,
+ ntohs(request->length));
+ assert(!error);
+
+ reply_raw = ofpraw_stats_request_to_reply(request_raw, request->version);
+ assert(reply_raw);
+
+ return ofpraw_alloc_reply(reply_raw, request, extra_tailroom);
+}
+
+/* Appends to 'buf' an OpenFlow header for 'raw' with OpenFlow version
+ * 'version' and a fresh OpenFlow transaction ID. Preallocates enough tailroom
+ * in 'buf' for the minimum body length of 'raw', plus 'extra_tailroom'
+ * additional bytes.
+ *
+ * Each 'raw' value is valid only for certain OpenFlow versions. The caller
+ * must specify a valid (raw, version) pair.
+ *
+ * Upon return, 'buf->l2' points to the beginning of the OpenFlow header and
+ * 'buf->l3' points just after it, to where the message's body will start. The
+ * caller must actually allocating the body into the space reserved for it,
+ * e.g. with ofpbuf_put_uninit(). */
+void
+ofpraw_put(enum ofpraw raw, uint8_t version, struct ofpbuf *buf)
+{
+ ofpraw_put__(raw, version, alloc_xid(), 0, buf);
+}
+
+/* Same as ofpraw_put() but the caller provides the transaction ID. */
+void
+ofpraw_put_xid(enum ofpraw raw, uint8_t version, ovs_be32 xid,
+ struct ofpbuf *buf)
+{
+ ofpraw_put__(raw, version, xid, 0, buf);
+}
+
+/* Same as ofpraw_put(), but obtains the OpenFlow version and transaction ID
+ * from 'request->version' and 'request->xid', respectively.
+ *
+ * Even though the version comes from 'request->version', the caller must still
+ * know what it is doing, by specifying a valid pairing of 'raw' and
+ * 'request->version', just like ofpraw_put(). */
+void
+ofpraw_put_reply(enum ofpraw raw, const struct ofp_header *request,
+ struct ofpbuf *buf)
+{
+ ofpraw_put__(raw, request->version, request->xid, 0, buf);
+}
+
+/* Appends to 'buf' an OpenFlow header that is a stats reply to the stats
+ * request in 'request', using the same OpenFlow version and transaction ID as
+ * 'request'. Preallocate enough tailroom in 'buf for the stats reply's
+ * minimum body length, plus 'extra_tailroom' additional bytes.
+ *
+ * 'request' must be a stats request, that is, an OFPRAW_OFPST* or OFPRAW_NXST*
+ * value. Every stats request has a corresponding reply, so the (raw, version)
+ * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here.
+ *
+ * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header
+ * and 'l3' points just after it, to where the message's body will start. The
+ * caller must actually allocate the body into the space reserved for it,
+ * e.g. with ofpbuf_put_uninit().
+ *
+ * The caller owns the returned ofpbuf and must free it when it is no longer
+ * needed, e.g. with ofpbuf_delete(). */
+void
+ofpraw_put_stats_reply(const struct ofp_header *request, struct ofpbuf *buf)
+{
+ enum ofperr error;
+ enum ofpraw raw;
+
+ error = ofpraw_decode_partial(&raw, request, ntohs(request->length));
+ assert(!error);
+
+ raw = ofpraw_stats_request_to_reply(raw, request->version);
+ assert(raw);
+
+ ofpraw_put__(raw, request->version, request->xid, 0, buf);
+}
+
+static void
+ofpraw_put__(enum ofpraw raw, uint8_t version, ovs_be32 xid,
+ size_t extra_tailroom, struct ofpbuf *buf)
+{
+ const struct raw_info *info = raw_info_get(raw);
+ const struct raw_instance *instance = raw_instance_get(info, version);
+ const struct ofphdrs *hdrs = &instance->hdrs;
+ struct ofp_header *oh;
+
+ ofpbuf_prealloc_tailroom(buf, (instance->hdrs_len + info->min_body
+ + extra_tailroom));
+ buf->l2 = ofpbuf_put_uninit(buf, instance->hdrs_len);
+ buf->l3 = ofpbuf_tail(buf);
+
+ oh = buf->l2;
+ oh->version = version;
+ oh->type = hdrs->type;
+ oh->length = htons(buf->size);
+ oh->xid = xid;
+
+ if (hdrs->type == OFPT_VENDOR) {
+ struct nicira_header *nh = buf->l2;
+
+ assert(hdrs->vendor == NX_VENDOR_ID);
+ nh->vendor = htonl(hdrs->vendor);
+ nh->subtype = htonl(hdrs->subtype);
+ } else if (version == OFP10_VERSION
+ && (hdrs->type == OFPT10_STATS_REQUEST ||
+ hdrs->type == OFPT10_STATS_REPLY)) {
+ struct ofp_stats_msg *osm = buf->l2;
+
+ osm->type = htons(hdrs->stat);
+ osm->flags = htons(0);
+
+ if (hdrs->stat == OFPST_VENDOR) {
+ struct ofp10_vendor_stats_msg *ovsm = buf->l2;
+
+ ovsm->vendor = htonl(hdrs->vendor);
+ if (hdrs->vendor == NX_VENDOR_ID) {
+ struct nicira10_stats_msg *nsm = buf->l2;
+
+ nsm->subtype = htonl(hdrs->subtype);
+ memset(nsm->pad, 0, sizeof nsm->pad);
+ } else {
+ NOT_REACHED();
+ }
+ }
+ } else if (version != OFP10_VERSION
+ && (hdrs->type == OFPT11_STATS_REQUEST ||
+ hdrs->type == OFPT11_STATS_REPLY)) {
+ struct ofp11_stats_msg *osm = buf->l2;
+
+ osm->type = htons(hdrs->stat);
+ osm->flags = htons(0);
+ memset(osm->pad, 0, sizeof osm->pad);
+
+ if (hdrs->stat == OFPST_VENDOR) {
+ struct ofp11_vendor_stats_msg *ovsm = buf->l2;
+
+ ovsm->vendor = htonl(hdrs->vendor);
+ if (hdrs->vendor == NX_VENDOR_ID) {
+ struct nicira11_stats_msg *nsm = buf->l2;
+
+ nsm->subtype = htonl(hdrs->subtype);
+ } else {
+ NOT_REACHED();
+ }
+ }
+ }
+}
+\f
+/* Returns 'raw''s name.
+ *
+ * The name is the name used for 'raw' in the OpenFlow specification. For
+ * example, ofpraw_get_name(OFPRAW_OFPT10_FEATURES_REPLY) is
+ * "OFPT_FEATURES_REPLY".
+ *
+ * The caller must not modify or free the returned string. */
+const char *
+ofpraw_get_name(enum ofpraw raw)
+{
+ return raw_info_get(raw)->name;
+}
+
+/* Returns the stats reply that corresponds to 'raw' in the given OpenFlow
+ * 'version'. */
+enum ofpraw
+ofpraw_stats_request_to_reply(enum ofpraw raw, uint8_t version)
+{
+ const struct raw_info *info = raw_info_get(raw);
+ const struct raw_instance *instance = raw_instance_get(info, version);
+ enum ofpraw reply_raw;
+ struct ofphdrs hdrs;
+ enum ofperr error;
+
+ hdrs = instance->hdrs;
+ if (hdrs.version == OFP10_VERSION) {
+ assert(hdrs.type == OFPT10_STATS_REQUEST);
+ hdrs.type = OFPT10_STATS_REPLY;
+ } else {
+ assert(hdrs.type == OFPT11_STATS_REQUEST);
+ hdrs.type = OFPT11_STATS_REPLY;
+ }
+
+ error = ofpraw_from_ofphdrs(&reply_raw, &hdrs);
+ assert(!error);
+
+ return reply_raw;
+}
+\f
+/* Determines the OFPTYPE_* type of the OpenFlow message at 'oh', which has
+ * length 'oh->length'. (The caller must ensure that 'oh->length' bytes of
+ * data are readable at 'oh'.) On success, returns 0 and stores the type into
+ * '*typep'. On failure, returns an OFPERR_* error code and zeros '*typep'.
+ *
+ * This function checks that 'oh' is a valid length for its particular type of
+ * message, and returns an error if not. */
+enum ofperr
+ofptype_decode(enum ofptype *typep, const struct ofp_header *oh)
+{
+ enum ofperr error;
+ enum ofpraw raw;
+
+ error = ofpraw_decode(&raw, oh);
+ *typep = error ? 0 : ofptype_from_ofpraw(raw);
+ return error;
+}
+
+/* Determines the OFPTYPE_* type of the OpenFlow message in 'msg', which starts
+ * at 'msg->data' and has length 'msg->size' bytes. On success, returns 0 and
+ * stores the type into '*typep'. On failure, returns an OFPERR_* error code
+ * and zeros '*typep'.
+ *
+ * This function checks that the message has a valid length for its particular
+ * type of message, and returns an error if not.
+ *
+ * In addition to setting '*typep', this function pulls off the OpenFlow header
+ * (including the stats headers, vendor header, and any subtype header) with
+ * ofpbuf_pull(). It also sets 'msg->l2' to the start of the OpenFlow header
+ * and 'msg->l3' just beyond the headers (that is, to the final value of
+ * msg->data). */
+enum ofperr
+ofptype_pull(enum ofptype *typep, struct ofpbuf *buf)
+{
+ enum ofperr error;
+ enum ofpraw raw;
+
+ error = ofpraw_pull(&raw, buf);
+ *typep = error ? 0 : ofptype_from_ofpraw(raw);
+ return error;
+}
+
+/* Returns the OFPTYPE_* type that corresponds to 'raw'.
+ *
+ * (This is a one-way trip, because the mapping from ofpraw to ofptype is
+ * many-to-one.) */
+enum ofptype
+ofptype_from_ofpraw(enum ofpraw raw)
+{
+ return raw_info_get(raw)->type;
+}
+\f
+/* Updates the 'length' field of the OpenFlow message in 'buf' to
+ * 'buf->size'. */
+void
+ofpmsg_update_length(struct ofpbuf *buf)
+{
+ struct ofp_header *oh = ofpbuf_at_assert(buf, 0, sizeof *oh);
+ oh->length = htons(buf->size);
+}
+
+/* Returns just past the Openflow header (including the stats headers, vendor
+ * header, and any subtype header) in 'oh'. */
+const void *
+ofpmsg_body(const struct ofp_header *oh)
+{
+ struct ofphdrs hdrs;
+
+ ofphdrs_decode_assert(&hdrs, oh, ntohs(oh->length));
+ return (const uint8_t *) oh + ofphdrs_len(&hdrs);
+}
+\f
+/* Initializes 'replies' as a new list of stats messages that reply to
+ * 'request', which must be a stats request message. Initially the list will
+ * consist of only a single reply part without any body. The caller should
+ * use calls to the other ofpmp_*() functions to add to the body and split the
+ * message into multiple parts, if necessary. */
+void
+ofpmp_init(struct list *replies, const struct ofp_header *request)
+{
+ struct ofpbuf *msg;
+
+ list_init(replies);
+
+ msg = ofpraw_alloc_stats_reply(request, 1000);
+ list_push_back(replies, &msg->list_node);
+}
+
+/* Prepares to append up to 'len' bytes to the series of statistics replies in
+ * 'replies', which should have been initialized with ofpmp_init(), if
+ * necessary adding a new reply to the list.
+ *
+ * Returns an ofpbuf with at least 'len' bytes of tailroom. The 'len' bytes
+ * have not actually been allocated, so the caller must do so with
+ * e.g. ofpbuf_put_uninit(). */
+struct ofpbuf *
+ofpmp_reserve(struct list *replies, size_t len)
+{
+ struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
+
+ if (msg->size + len <= UINT16_MAX) {
+ ofpbuf_prealloc_tailroom(msg, len);
+ return msg;
+ } else {
+ unsigned int hdrs_len;
+ struct ofpbuf *next;
+ struct ofphdrs hdrs;
+
+ ofphdrs_decode_assert(&hdrs, msg->data, msg->size);
+ hdrs_len = ofphdrs_len(&hdrs);
+
+ next = ofpbuf_new(MAX(1024, hdrs_len + len));
+ ofpbuf_put(next, msg->data, hdrs_len);
+ list_push_back(replies, &next->list_node);
+
+ return next;
+ }
+}
+
+/* Appends 'len' bytes to the series of statistics replies in 'replies', and
+ * returns the first byte. */
+void *
+ofpmp_append(struct list *replies, size_t len)
+{
+ return ofpbuf_put_uninit(ofpmp_reserve(replies, len), len);
+}
+
+/* Sometimes, when composing stats replies, it's difficult to predict how long
+ * an individual reply chunk will be before actually encoding it into the reply
+ * buffer. This function allows easy handling of this case: just encode the
+ * reply, then use this function to break the message into two pieces if it
+ * exceeds the OpenFlow message limit.
+ *
+ * In detail, if the final stats message in 'replies' is too long for OpenFlow,
+ * this function breaks it into two separate stats replies, the first one with
+ * the first 'start_ofs' bytes, the second one containing the bytes from that
+ * offset onward. */
+void
+ofpmp_postappend(struct list *replies, size_t start_ofs)
+{
+ struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
+
+ assert(start_ofs <= UINT16_MAX);
+ if (msg->size > UINT16_MAX) {
+ size_t len = msg->size - start_ofs;
+ memcpy(ofpmp_append(replies, len),
+ (const uint8_t *) msg->data + start_ofs, len);
+ msg->size = start_ofs;
+ }
+}
+
+static ovs_be16 *
+ofpmp_flags__(const struct ofp_header *oh)
+{
+ return (oh->version == OFP10_VERSION
+ ? &((struct ofp_stats_msg *) oh)->flags
+ : &((struct ofp11_stats_msg *) oh)->flags);
+}
+
+/* Returns the OFPSF_* flags found in the OpenFlow stats header of 'oh', which
+ * must be an OpenFlow stats request or reply.
+ *
+ * (OFPSF_REPLY_MORE is the only defined flag.) */
+uint16_t
+ofpmp_flags(const struct ofp_header *oh)
+{
+ return ntohs(*ofpmp_flags__(oh));
+}
+
+/* Returns true if the OFPSF_REPLY_MORE flag is set in the OpenFlow stats
+ * header of 'oh', which must be an OpenFlow stats request or reply, false if
+ * it is not set. */
+bool
+ofpmp_more(const struct ofp_header *oh)
+{
+ return (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0;
+}
+\f
+static void ofpmsgs_init(void);
+
+static const struct raw_info *
+raw_info_get(enum ofpraw raw)
+{
+ ofpmsgs_init();
+
+ assert(raw < ARRAY_SIZE(raw_infos));
+ return &raw_infos[raw];
+}
+
+static struct raw_instance *
+raw_instance_get(const struct raw_info *info, uint8_t version)
+{
+ assert(version >= info->min_version && version <= info->max_version);
+ return &info->instances[version - info->min_version];
+}
+
+static enum ofperr
+ofpraw_from_ofphdrs(enum ofpraw *raw, const struct ofphdrs *hdrs)
+{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+
+ struct raw_instance *raw_hdrs;
+ uint32_t hash;
+
+ ofpmsgs_init();
+
+ hash = ofphdrs_hash(hdrs);
+ HMAP_FOR_EACH_WITH_HASH (raw_hdrs, hmap_node, hash, &raw_instance_map) {
+ if (ofphdrs_equal(hdrs, &raw_hdrs->hdrs)) {
+ *raw = raw_hdrs->raw;
+ return 0;
+ }
+ }
+
+ if (!VLOG_DROP_WARN(&rl)) {
+ struct ds s;
+
+ ds_init(&s);
+ ds_put_format(&s, "version %"PRIu8", type %"PRIu8,
+ hdrs->version, hdrs->type);
+ if (ofphdrs_is_stat(hdrs)) {
+ ds_put_format(&s, ", stat %"PRIu16, hdrs->stat);
+ }
+ if (hdrs->vendor) {
+ ds_put_format(&s, ", vendor 0x%"PRIx32", subtype %"PRIu32,
+ hdrs->vendor, hdrs->subtype);
+ }
+ VLOG_WARN("unknown OpenFlow message (%s)", ds_cstr(&s));
+ ds_destroy(&s);
+ }
+
+ return (hdrs->vendor ? OFPERR_OFPBRC_BAD_SUBTYPE
+ : ofphdrs_is_stat(hdrs) ? OFPERR_OFPBRC_BAD_STAT
+ : OFPERR_OFPBRC_BAD_TYPE);
+}
+
+static void
+ofpmsgs_init(void)
+{
+ const struct raw_info *info;
+
+ if (raw_instance_map.buckets) {
+ return;
+ }
+
+ hmap_init(&raw_instance_map);
+ for (info = raw_infos; info < &raw_infos[ARRAY_SIZE(raw_infos)]; info++)
+ {
+ int n_instances = info->max_version - info->min_version + 1;
+ struct raw_instance *inst;
+
+ for (inst = info->instances;
+ inst < &info->instances[n_instances];
+ inst++) {
+ inst->hdrs_len = ofphdrs_len(&inst->hdrs);
+ hmap_insert(&raw_instance_map, &inst->hmap_node,
+ ofphdrs_hash(&inst->hdrs));
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2012 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFP_MSGS_H
+#define OFP_MSGS_H 1
+
+/* OpenFlow message headers abstraction.
+ *
+ * OpenFlow headers are unnecessarily complicated:
+ *
+ * - Some messages with the same meaning were renumbered between 1.0 and 1.1.
+ *
+ * - "Statistics" (aka multipart) messages have a different format from other
+ * messages.
+ *
+ * - The 1.0 header for statistics messages is an odd number of 32-bit words
+ * long, leaving 64-bit quantities in the body misaligned. The 1.1 header
+ * for statistics added a padding word to fix this misalignment, although
+ * many statistic message bodies did not change.
+ *
+ * - Vendor-defined messages have an additional header but no standard way to
+ * distinguish individual types of message within a given vendor.
+ *
+ * This file attempts to abstract out the differences between the various forms
+ * of headers.
+ */
+
+#include "openvswitch/types.h"
+#include "ofp-errors.h"
+#include "util.h"
+
+struct list;
+\f
+/* Raw identifiers for OpenFlow messages.
+ *
+ * Some OpenFlow messages with similar meanings have multiple variants across
+ * OpenFlow versions or vendor extensions. Each variant has a different
+ * OFPRAW_* enumeration constant. More specifically, if two messages have
+ * different types, different numbers, or different arguments, then they must
+ * have different OFPRAW_* values.
+ *
+ * The comments here must follow a stylized form because the "extract-ofp-msgs"
+ * program parses them at build time to generate data tables. The syntax of
+ * each comment is:
+ *
+ * type versions (number): arguments.
+ *
+ * where the syntax of each part is:
+ *
+ * - type: One of OFPT (standard OpenFlow message), OFPST (standard OpenFlow
+ * statistics message), NXT (Nicira extension message), or NXST (Nicira
+ * extension statistics message).
+ *
+ * As new vendors implement extensions it will make sense to expand the
+ * dictionary of possible types.
+ *
+ * - versions: The OpenFlow version or versions in which this message is
+ * supported, e.g. "1.0" or "1.1" or "1.0+".
+ *
+ * - number:
+ * For OFPT, the 'type' in struct ofp_header.
+ * For OFPST, the 'type' in struct ofp_stats_msg or ofp11_stats_msg.
+ * For NXT, the 'subtype' in struct nicira_header.
+ * For NXST, the 'subtype' in struct nicira10_stats_msg or
+ * nicira11_stats_msg.
+ *
+ * - arguments: The types of data that follow the OpenFlow headers (the
+ * message "body"). This can be "void" if the message has no body.
+ * Otherwise, it should be a comma-separated sequence of C types. The
+ * last type in the sequence can end with [] if the body ends in a
+ * variable-length sequence.
+ *
+ * The arguments are used to validate the lengths of messages when a
+ * header is parsed. Any message whose length isn't valid as a length of
+ * the specified types will be rejected with OFPERR_OFPBRC_BAD_LEN.
+ *
+ * A few OpenFlow messages, such as OFPT_PACKET_IN, intentionally end with
+ * only part of a structure, up to some specified member. The syntax "up
+ * to <member>" indicates this, e.g. "struct ofp11_packet_in up to data".
+ */
+enum ofpraw {
+/* Standard messages. */
+
+ /* OFPT 1.0+ (0): uint8_t[]. */
+ OFPRAW_OFPT_HELLO,
+
+ /* OFPT 1.0+ (1): struct ofp_error_msg, uint8_t[]. */
+ OFPRAW_OFPT_ERROR,
+
+ /* OFPT 1.0+ (2): uint8_t[]. */
+ OFPRAW_OFPT_ECHO_REQUEST,
+
+ /* OFPT 1.0+ (3): uint8_t[]. */
+ OFPRAW_OFPT_ECHO_REPLY,
+
+ /* OFPT 1.0+ (5): void. */
+ OFPRAW_OFPT_FEATURES_REQUEST,
+
+ /* OFPT 1.0 (6): struct ofp_switch_features, struct ofp10_phy_port[]. */
+ OFPRAW_OFPT10_FEATURES_REPLY,
+ /* OFPT 1.1+ (6): struct ofp_switch_features, struct ofp11_port[]. */
+ OFPRAW_OFPT11_FEATURES_REPLY,
+
+ /* OFPT 1.0+ (7): void. */
+ OFPRAW_OFPT_GET_CONFIG_REQUEST,
+
+ /* OFPT 1.0+ (8): struct ofp_switch_config. */
+ OFPRAW_OFPT_GET_CONFIG_REPLY,
+
+ /* OFPT 1.0-1.1 (9): struct ofp_switch_config. */
+ OFPRAW_OFPT_SET_CONFIG,
+
+ /* OFPT 1.0 (10): struct ofp_packet_in up to data, uint8_t[]. */
+ OFPRAW_OFPT10_PACKET_IN,
+ /* OFPT 1.1 (10): struct ofp11_packet_in up to data, uint8_t[]. */
+ OFPRAW_OFPT11_PACKET_IN,
+ /* NXT 1.0+ (17): struct nx_packet_in, uint8_t[]. */
+ OFPRAW_NXT_PACKET_IN,
+
+ /* OFPT 1.0 (11): struct ofp_flow_removed. */
+ OFPRAW_OFPT10_FLOW_REMOVED,
+ /* NXT 1.0+ (14): struct nx_flow_removed, uint8_t[8][]. */
+ OFPRAW_NXT_FLOW_REMOVED,
+
+ /* OFPT 1.0 (12): struct ofp_port_status, struct ofp10_phy_port. */
+ OFPRAW_OFPT10_PORT_STATUS,
+ /* OFPT 1.1+ (12): struct ofp_port_status, struct ofp11_port. */
+ OFPRAW_OFPT11_PORT_STATUS,
+
+ /* OFPT 1.0 (13): struct ofp_packet_out, uint8_t[]. */
+ OFPRAW_OFPT10_PACKET_OUT,
+ /* OFPT 1.1+ (13): struct ofp11_packet_out, uint8_t[]. */
+ OFPRAW_OFPT11_PACKET_OUT,
+
+ /* OFPT 1.0 (14): struct ofp_flow_mod, struct ofp_action_header[]. */
+ OFPRAW_OFPT10_FLOW_MOD,
+ /* OFPT 1.1+ (14): struct ofp11_flow_mod, struct ofp11_instruction[]. */
+ OFPRAW_OFPT11_FLOW_MOD,
+ /* NXT 1.0+ (13): struct nx_flow_mod, uint8_t[8][]. */
+ OFPRAW_NXT_FLOW_MOD,
+
+ /* OFPT 1.0 (15): struct ofp10_port_mod. */
+ OFPRAW_OFPT10_PORT_MOD,
+ /* OFPT 1.1 (16): struct ofp11_port_mod. */
+ OFPRAW_OFPT11_PORT_MOD,
+
+ /* OFPT 1.0 (18): void. */
+ OFPRAW_OFPT10_BARRIER_REQUEST,
+ /* OFPT 1.1 (20): void. */
+ OFPRAW_OFPT11_BARRIER_REQUEST,
+
+ /* OFPT 1.0 (19): void. */
+ OFPRAW_OFPT10_BARRIER_REPLY,
+ /* OFPT 1.1 (21): void. */
+ OFPRAW_OFPT11_BARRIER_REPLY,
+
+/* Standard statistics. */
+
+ /* OFPST 1.0+ (0): void. */
+ OFPRAW_OFPST_DESC_REQUEST,
+
+ /* OFPST 1.0+ (0): struct ofp_desc_stats. */
+ OFPRAW_OFPST_DESC_REPLY,
+
+ /* OFPST 1.0 (1): struct ofp_flow_stats_request. */
+ OFPRAW_OFPST_FLOW_REQUEST,
+ /* NXST 1.0 (0): struct nx_flow_stats_request, uint8_t[8][]. */
+ OFPRAW_NXST_FLOW_REQUEST,
+
+ /* OFPST 1.0 (1): uint8_t[]. */
+ OFPRAW_OFPST_FLOW_REPLY,
+ /* NXST 1.0 (0): uint8_t[]. */
+ OFPRAW_NXST_FLOW_REPLY,
+
+ /* OFPST 1.0 (2): struct ofp_flow_stats_request. */
+ OFPRAW_OFPST_AGGREGATE_REQUEST,
+ /* NXST 1.0 (1): struct nx_flow_stats_request, uint8_t[8][]. */
+ OFPRAW_NXST_AGGREGATE_REQUEST,
+
+ /* OFPST 1.0 (2): struct ofp_aggregate_stats_reply. */
+ OFPRAW_OFPST_AGGREGATE_REPLY,
+ /* NXST 1.0 (1): struct nx_aggregate_stats_reply. */
+ OFPRAW_NXST_AGGREGATE_REPLY,
+
+ /* OFPST 1.0 (3): void. */
+ OFPRAW_OFPST_TABLE_REQUEST,
+
+ /* OFPST 1.0 (3): struct ofp_table_stats[]. */
+ OFPRAW_OFPST_TABLE_REPLY,
+
+ /* OFPST 1.0 (4): struct ofp_port_stats_request. */
+ OFPRAW_OFPST_PORT_REQUEST,
+
+ /* OFPST 1.0 (4): struct ofp_port_stats[]. */
+ OFPRAW_OFPST_PORT_REPLY,
+
+ /* OFPST 1.0 (5): struct ofp_queue_stats_request. */
+ OFPRAW_OFPST_QUEUE_REQUEST,
+
+ /* OFPST 1.0 (5): struct ofp_queue_stats[]. */
+ OFPRAW_OFPST_QUEUE_REPLY,
+
+ /* OFPST 1.0 (13): void. */
+ OFPRAW_OFPST_PORT_DESC_REQUEST,
+
+ /* OFPST 1.0 (13): struct ofp10_phy_port[]. */
+ OFPRAW_OFPST_PORT_DESC_REPLY,
+
+/* Nicira extension messages.
+ *
+ * Nicira extensions that correspond to standard OpenFlow messages are listed
+ * alongside the standard versions above. */
+
+ /* NXT 1.0+ (10): struct nx_role_request. */
+ OFPRAW_NXT_ROLE_REQUEST,
+
+ /* NXT 1.0+ (11): struct nx_role_request. */
+ OFPRAW_NXT_ROLE_REPLY,
+
+ /* NXT 1.0+ (12): struct nx_set_flow_format. */
+ OFPRAW_NXT_SET_FLOW_FORMAT,
+
+ /* NXT 1.0+ (15): struct nx_flow_mod_table_id. */
+ OFPRAW_NXT_FLOW_MOD_TABLE_ID,
+
+ /* NXT 1.0+ (16): struct nx_set_packet_in_format. */
+ OFPRAW_NXT_SET_PACKET_IN_FORMAT,
+
+ /* NXT 1.0+ (18): void. */
+ OFPRAW_NXT_FLOW_AGE,
+
+ /* NXT 1.0+ (19): struct nx_async_config. */
+ OFPRAW_NXT_SET_ASYNC_CONFIG,
+
+ /* NXT 1.0+ (20): struct nx_controller_id. */
+ OFPRAW_NXT_SET_CONTROLLER_ID,
+
+ /* NXT 1.0+ (21): struct nx_flow_monitor_cancel. */
+ OFPRAW_NXT_FLOW_MONITOR_CANCEL,
+
+ /* NXT 1.0+ (22): void. */
+ OFPRAW_NXT_FLOW_MONITOR_PAUSED,
+
+ /* NXT 1.0+ (23): void. */
+ OFPRAW_NXT_FLOW_MONITOR_RESUMED,
+
+/* Nicira extension statistics.
+ *
+ * Nicira extension statistics that correspond to standard OpenFlow statistics
+ * are listed alongside the standard versions above. */
+
+ /* NXST 1.0 (2): uint8_t[8][]. */
+ OFPRAW_NXST_FLOW_MONITOR_REQUEST,
+
+ /* NXST 1.0 (2): uint8_t[8][]. */
+ OFPRAW_NXST_FLOW_MONITOR_REPLY,
+};
+
+/* Decoding messages into OFPRAW_* values. */
+enum ofperr ofpraw_decode(enum ofpraw *, const struct ofp_header *);
+enum ofperr ofpraw_pull(enum ofpraw *, struct ofpbuf *);
+enum ofpraw ofpraw_pull_assert(struct ofpbuf *);
+
+enum ofperr ofpraw_decode_partial(enum ofpraw *,
+ const struct ofp_header *, size_t length);
+
+/* Encoding messages using OFPRAW_* values. */
+struct ofpbuf *ofpraw_alloc(enum ofpraw, uint8_t ofp_version,
+ size_t extra_tailroom);
+struct ofpbuf *ofpraw_alloc_xid(enum ofpraw, uint8_t ofp_version,
+ ovs_be32 xid, size_t extra_tailroom);
+struct ofpbuf *ofpraw_alloc_reply(enum ofpraw,
+ const struct ofp_header *request,
+ size_t extra_tailroom);
+struct ofpbuf *ofpraw_alloc_stats_reply(const struct ofp_header *request,
+ size_t extra_tailroom);
+
+void ofpraw_put(enum ofpraw, uint8_t ofp_version, struct ofpbuf *);
+void ofpraw_put_xid(enum ofpraw, uint8_t ofp_version, ovs_be32 xid,
+ struct ofpbuf *);
+void ofpraw_put_reply(enum ofpraw, const struct ofp_header *request,
+ struct ofpbuf *);
+void ofpraw_put_stats_reply(const struct ofp_header *request, struct ofpbuf *);
+
+/* Information about OFPRAW_* values. */
+const char *ofpraw_get_name(enum ofpraw);
+enum ofpraw ofpraw_stats_request_to_reply(enum ofpraw, uint8_t version);
+\f
+/* Semantic identifiers for OpenFlow messages.
+ *
+ * Each OFPTYPE_* enumeration constant represents one or more concrete format
+ * of OpenFlow message. When two variants of a message have essentially the
+ * same meaning, they are assigned a single OFPTYPE_* value.
+ *
+ * The comments here must follow a stylized form because the "extract-ofp-msgs"
+ * program parses them at build time to generate data tables. The format is
+ * simply to list each OFPRAW_* enumeration constant for a given OFPTYPE_*,
+ * each followed by a period. */
+enum ofptype {
+ /* Immutable messages. */
+ OFPTYPE_HELLO, /* OFPRAW_OFPT_HELLO. */
+ OFPTYPE_ERROR, /* OFPRAW_OFPT_ERROR. */
+ OFPTYPE_ECHO_REQUEST, /* OFPRAW_OFPT_ECHO_REQUEST. */
+ OFPTYPE_ECHO_REPLY, /* OFPRAW_OFPT_ECHO_REPLY. */
+
+ /* Switch configuration messages. */
+ OFPTYPE_FEATURES_REQUEST, /* OFPRAW_OFPT_FEATURES_REQUEST. */
+ OFPTYPE_FEATURES_REPLY, /* OFPRAW_OFPT10_FEATURES_REPLY.
+ * OFPRAW_OFPT11_FEATURES_REPLY. */
+ OFPTYPE_GET_CONFIG_REQUEST, /* OFPRAW_OFPT_GET_CONFIG_REQUEST. */
+ OFPTYPE_GET_CONFIG_REPLY, /* OFPRAW_OFPT_GET_CONFIG_REPLY. */
+ OFPTYPE_SET_CONFIG, /* OFPRAW_OFPT_SET_CONFIG. */
+
+ /* Asynchronous messages. */
+ OFPTYPE_PACKET_IN, /* OFPRAW_OFPT10_PACKET_IN.
+ * OFPRAW_OFPT11_PACKET_IN.
+ * OFPRAW_NXT_PACKET_IN. */
+ OFPTYPE_FLOW_REMOVED, /* OFPRAW_OFPT10_FLOW_REMOVED.
+ * OFPRAW_NXT_FLOW_REMOVED. */
+ OFPTYPE_PORT_STATUS, /* OFPRAW_OFPT10_PORT_STATUS.
+ * OFPRAW_OFPT11_PORT_STATUS. */
+
+ /* Controller command messages. */
+ OFPTYPE_PACKET_OUT, /* OFPRAW_OFPT10_PACKET_OUT.
+ * OFPRAW_OFPT11_PACKET_OUT. */
+ OFPTYPE_FLOW_MOD, /* OFPRAW_OFPT10_FLOW_MOD.
+ * OFPRAW_OFPT11_FLOW_MOD.
+ * OFPRAW_NXT_FLOW_MOD. */
+ OFPTYPE_PORT_MOD, /* OFPRAW_OFPT10_PORT_MOD.
+ * OFPRAW_OFPT11_PORT_MOD. */
+
+ /* Barrier messages. */
+ OFPTYPE_BARRIER_REQUEST, /* OFPRAW_OFPT10_BARRIER_REQUEST.
+ * OFPRAW_OFPT11_BARRIER_REQUEST. */
+ OFPTYPE_BARRIER_REPLY, /* OFPRAW_OFPT10_BARRIER_REPLY.
+ * OFPRAW_OFPT11_BARRIER_REPLY. */
+
+ /* Statistics. */
+ OFPTYPE_DESC_STATS_REQUEST, /* OFPRAW_OFPST_DESC_REQUEST. */
+ OFPTYPE_DESC_STATS_REPLY, /* OFPRAW_OFPST_DESC_REPLY. */
+ OFPTYPE_FLOW_STATS_REQUEST, /* OFPRAW_OFPST_FLOW_REQUEST.
+ * OFPRAW_NXST_FLOW_REQUEST. */
+ OFPTYPE_FLOW_STATS_REPLY, /* OFPRAW_OFPST_FLOW_REPLY.
+ * OFPRAW_NXST_FLOW_REPLY. */
+ OFPTYPE_AGGREGATE_STATS_REQUEST, /* OFPRAW_OFPST_AGGREGATE_REQUEST.
+ * OFPRAW_NXST_AGGREGATE_REQUEST. */
+ OFPTYPE_AGGREGATE_STATS_REPLY, /* OFPRAW_OFPST_AGGREGATE_REPLY.
+ * OFPRAW_NXST_AGGREGATE_REPLY. */
+ OFPTYPE_TABLE_STATS_REQUEST, /* OFPRAW_OFPST_TABLE_REQUEST. */
+ OFPTYPE_TABLE_STATS_REPLY, /* OFPRAW_OFPST_TABLE_REPLY. */
+ OFPTYPE_PORT_STATS_REQUEST, /* OFPRAW_OFPST_PORT_REQUEST. */
+ OFPTYPE_PORT_STATS_REPLY, /* OFPRAW_OFPST_PORT_REPLY. */
+ OFPTYPE_QUEUE_STATS_REQUEST, /* OFPRAW_OFPST_QUEUE_REQUEST. */
+ OFPTYPE_QUEUE_STATS_REPLY, /* OFPRAW_OFPST_QUEUE_REPLY. */
+ OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST_PORT_DESC_REQUEST. */
+ OFPTYPE_PORT_DESC_STATS_REPLY, /* OFPRAW_OFPST_PORT_DESC_REPLY. */
+
+ /* Nicira extensions. */
+ OFPTYPE_ROLE_REQUEST, /* OFPRAW_NXT_ROLE_REQUEST. */
+ OFPTYPE_ROLE_REPLY, /* OFPRAW_NXT_ROLE_REPLY. */
+ OFPTYPE_SET_FLOW_FORMAT, /* OFPRAW_NXT_SET_FLOW_FORMAT. */
+ OFPTYPE_FLOW_MOD_TABLE_ID, /* OFPRAW_NXT_FLOW_MOD_TABLE_ID. */
+ OFPTYPE_SET_PACKET_IN_FORMAT, /* OFPRAW_NXT_SET_PACKET_IN_FORMAT. */
+ OFPTYPE_FLOW_AGE, /* OFPRAW_NXT_FLOW_AGE. */
+ OFPTYPE_SET_ASYNC_CONFIG, /* OFPRAW_NXT_SET_ASYNC_CONFIG. */
+ OFPTYPE_SET_CONTROLLER_ID, /* OFPRAW_NXT_SET_CONTROLLER_ID. */
+
+ /* Flow monitor extension. */
+ OFPTYPE_FLOW_MONITOR_STATS_REQUEST, /* OFPRAW_NXST_FLOW_MONITOR_REQUEST. */
+ OFPTYPE_FLOW_MONITOR_STATS_REPLY, /* OFPRAW_NXST_FLOW_MONITOR_REPLY. */
+ OFPTYPE_FLOW_MONITOR_CANCEL, /* OFPRAW_NXT_FLOW_MONITOR_CANCEL. */
+ OFPTYPE_FLOW_MONITOR_PAUSED, /* OFPRAW_NXT_FLOW_MONITOR_PAUSED. */
+ OFPTYPE_FLOW_MONITOR_RESUMED, /* OFPRAW_NXT_FLOW_MONITOR_RESUMED. */
+};
+
+/* Decoding messages into OFPTYPE_* values. */
+enum ofperr ofptype_decode(enum ofptype *, const struct ofp_header *);
+enum ofperr ofptype_pull(enum ofptype *, struct ofpbuf *);
+enum ofptype ofptype_from_ofpraw(enum ofpraw);
+\f
+/* OpenFlow message properties. */
+void ofpmsg_update_length(struct ofpbuf *);
+const void *ofpmsg_body(const struct ofp_header *);
+\f
+/* Multipart messages (aka "statistics").
+ *
+ * Individual OpenFlow messages are limited to 64 kB in size, but some messages
+ * need to be longer. Therefore, multipart messages allow a longer message to
+ * be divided into multiple parts at some convenient boundary. For example,
+ * limiting the response to a "flow dump" request to 64 kB would unreasonably
+ * limit the maximum number of flows in an OpenFlow switch, so a "flow dump" is
+ * expressed as a multipart request/reply pair, with the reply broken into
+ * pieces between flows.
+ *
+ * Multipart messages always consist of a request/reply pair.
+ *
+ * In OpenFlow 1.0, 1.1, and 1.2, requests must always fit in a single message,
+ * that is, only a multipart reply may have more than one part. OpenFlow 1.3
+ * adds one multipart request. This code does not yet support multipart
+ * requests. */
+
+/* Encoding multipart replies.
+ *
+ * These functions are useful for multipart replies that might really require
+ * more than one message. A multipart message that is known in advance to fit
+ * within 64 kB doesn't need any special treatment, so you might as well use
+ * the ofpraw_alloc_*() functions.
+ *
+ * These functions work with a "struct list" of "struct ofpbuf"s, each of
+ * which represents one part of a multipart message. */
+void ofpmp_init(struct list *, const struct ofp_header *request);
+struct ofpbuf *ofpmp_reserve(struct list *, size_t len);
+void *ofpmp_append(struct list *, size_t len);
+void ofpmp_postappend(struct list *, size_t start_ofs);
+
+/* Decoding multipart replies. */
+uint16_t ofpmp_flags(const struct ofp_header *);
+bool ofpmp_more(const struct ofp_header *);
+
+#endif /* ofp-msgs.h */
#include "nx-match.h"
#include "ofp-actions.h"
#include "ofp-errors.h"
+#include "ofp-msgs.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
}
static void
-ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
+ofp_print_packet_out(struct ds *string, const struct ofp_header *oh,
int verbosity)
{
struct ofputil_packet_out po;
enum ofperr error;
ofpbuf_init(&ofpacts, 64);
- error = ofputil_decode_packet_out(&po, opo, &ofpacts);
+ error = ofputil_decode_packet_out(&po, oh, &ofpacts);
if (error) {
ofpbuf_uninit(&ofpacts);
ofp_print_error(string, error);
}
static void
-ofp_print_switch_features(struct ds *string,
- const struct ofp_switch_features *osf)
+ofp_print_switch_features(struct ds *string, const struct ofp_header *oh)
{
struct ofputil_switch_features features;
enum ofperr error;
struct ofpbuf b;
- error = ofputil_decode_switch_features(osf, &features, &b);
+ error = ofputil_decode_switch_features(oh, &features, &b);
if (error) {
ofp_print_error(string, error);
return;
ofputil_action_bitmap_to_name, ' ');
ds_put_char(string, '\n');
- ofp_print_phy_ports(string, osf->header.version, &b);
+ ofp_print_phy_ports(string, oh->version, &b);
}
static void
}
static void
-ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
- enum ofputil_msg_code code, int verbosity)
+ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity)
{
struct ofputil_flow_mod fm;
struct ofpbuf ofpacts;
bool need_priority;
enum ofperr error;
+ enum ofpraw raw;
ofpbuf_init(&ofpacts, 64);
error = ofputil_decode_flow_mod(&fm, oh, OFPUTIL_P_OF10_TID, &ofpacts);
}
ds_put_char(s, ' ');
- if (verbosity >= 3 && code == OFPUTIL_OFPT_FLOW_MOD) {
- const struct ofp_flow_mod *ofm = (const struct ofp_flow_mod *) oh;
+ ofpraw_decode(&raw, oh);
+ if (verbosity >= 3 && raw == OFPRAW_OFPT10_FLOW_MOD) {
+ const struct ofp_flow_mod *ofm = ofpmsg_body(oh);
ofp10_match_print(s, &ofm->match, verbosity);
/* ofp_print_match() doesn't print priority. */
need_priority = true;
- } else if (verbosity >= 3 && code == OFPUTIL_NXT_FLOW_MOD) {
- const struct nx_flow_mod *nfm = (const struct nx_flow_mod *) oh;
+ } else if (verbosity >= 3 && raw == OFPRAW_NXT_FLOW_MOD) {
+ const struct nx_flow_mod *nfm = ofpmsg_body(oh);
const void *nxm = nfm + 1;
char *nxm_s;
}
static void
-ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
+ofp_print_error_msg(struct ds *string, const struct ofp_header *oh)
{
- size_t len = ntohs(oem->header.length);
- size_t payload_ofs, payload_len;
- const void *payload;
+ size_t len = ntohs(oh->length);
+ struct ofpbuf payload;
enum ofperr error;
char *s;
- error = ofperr_decode_msg(&oem->header, &payload_ofs);
+ error = ofperr_decode_msg(oh, &payload);
if (!error) {
ds_put_cstr(string, "***decode error***");
- ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true);
+ ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true);
return;
}
ds_put_format(string, " %s\n", ofperr_get_name(error));
- payload = (const uint8_t *) oem + payload_ofs;
- payload_len = len - payload_ofs;
if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) {
- ds_put_printable(string, payload, payload_len);
+ ds_put_printable(string, payload.data, payload.size);
} else {
- s = ofp_to_string(payload, payload_len, 1);
+ s = ofp_to_string(payload.data, payload.size, 1);
ds_put_cstr(string, s);
free(s);
}
}
static void
-ofp_print_port_status(struct ds *string, const struct ofp_port_status *ops)
+ofp_print_port_status(struct ds *string, const struct ofp_header *oh)
{
struct ofputil_port_status ps;
enum ofperr error;
- error = ofputil_decode_port_status(ops, &ps);
+ error = ofputil_decode_port_status(oh, &ps);
if (error) {
ofp_print_error(string, error);
return;
}
static void
-ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_desc_stats *ods)
+ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_header *oh)
{
+ const struct ofp_desc_stats *ods = ofpmsg_body(oh);
+
ds_put_char(string, '\n');
ds_put_format(string, "Manufacturer: %.*s\n",
(int) sizeof ods->mfr_desc, ods->mfr_desc);
}
static void
-ofp_print_flow_stats_request(struct ds *string,
- const struct ofp_stats_msg *osm)
+ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh)
{
struct ofputil_flow_stats_request fsr;
enum ofperr error;
- error = ofputil_decode_flow_stats_request(&fsr, &osm->header);
+ error = ofputil_decode_flow_stats_request(&fsr, oh);
if (error) {
ofp_print_error(string, error);
return;
}
static void
-ofp_print_ofpst_aggregate_reply(struct ds *string,
- const struct ofp_aggregate_stats_reply *asr)
+ofp_print_aggregate_stats_reply(struct ds *string, const struct ofp_header *oh)
{
- ds_put_format(string, " packet_count=%"PRIu64,
- ntohll(get_32aligned_be64(&asr->packet_count)));
- ds_put_format(string, " byte_count=%"PRIu64,
- ntohll(get_32aligned_be64(&asr->byte_count)));
- ds_put_format(string, " flow_count=%"PRIu32, ntohl(asr->flow_count));
-}
+ struct ofputil_aggregate_stats as;
+ enum ofperr error;
-static void
-ofp_print_nxst_aggregate_reply(struct ds *string,
- const struct nx_aggregate_stats_reply *nasr)
-{
- ds_put_format(string, " packet_count=%"PRIu64, ntohll(nasr->packet_count));
- ds_put_format(string, " byte_count=%"PRIu64, ntohll(nasr->byte_count));
- ds_put_format(string, " flow_count=%"PRIu32, ntohl(nasr->flow_count));
+ error = ofputil_decode_aggregate_stats_reply(&as, oh);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ ds_put_format(string, " packet_count=%"PRIu64, as.packet_count);
+ ds_put_format(string, " byte_count=%"PRIu64, as.byte_count);
+ ds_put_format(string, " flow_count=%"PRIu32, as.flow_count);
}
static void print_port_stat(struct ds *string, const char *leader,
}
static void
-ofp_print_ofpst_port_request(struct ds *string,
- const struct ofp_port_stats_request *psr)
+ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh)
{
+ const struct ofp_port_stats_request *psr = ofpmsg_body(oh);
ds_put_format(string, " port_no=%"PRIu16, ntohs(psr->port_no));
}
ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
int verbosity)
{
- const struct ofp_port_stats *ps = ofputil_stats_body(oh);
- size_t n = ofputil_stats_body_len(oh) / sizeof *ps;
+ struct ofp_port_stats *ps;
+ struct ofpbuf b;
+ size_t n;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ ofpraw_pull_assert(&b);
+
+ n = b.size / sizeof *ps;
ds_put_format(string, " %zu ports\n", n);
if (verbosity < 1) {
return;
}
- for (; n--; ps++) {
+ for (;;) {
+ ps = ofpbuf_try_pull(&b, sizeof *ps);
+ if (!ps) {
+ return;
+ }
+
ds_put_format(string, " port %2"PRIu16": ", ntohs(ps->port_no));
ds_put_cstr(string, "rx ");
ofp_print_ofpst_table_reply(struct ds *string, const struct ofp_header *oh,
int verbosity)
{
- const struct ofp_table_stats *ts = ofputil_stats_body(oh);
- size_t n = ofputil_stats_body_len(oh) / sizeof *ts;
+ struct ofp_table_stats *ts;
+ struct ofpbuf b;
+ size_t n;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ ofpraw_pull_assert(&b);
+
+ n = b.size / sizeof *ts;
ds_put_format(string, " %zu tables\n", n);
if (verbosity < 1) {
return;
}
- for (; n--; ts++) {
+ for (;;) {
char name[OFP_MAX_TABLE_NAME_LEN + 1];
+
+ ts = ofpbuf_try_pull(&b, sizeof *ts);
+ if (!ts) {
+ return;
+ }
+
ovs_strlcpy(name, ts->name, sizeof name);
ds_put_format(string, " %d: %-8s: ", ts->table_id, name);
}
static void
-ofp_print_ofpst_queue_request(struct ds *string,
- const struct ofp_queue_stats_request *qsr)
+ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_header *oh)
{
+ const struct ofp_queue_stats_request *qsr = ofpmsg_body(oh);
+
ds_put_cstr(string, "port=");
ofputil_format_port(ntohs(qsr->port_no), string);
ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
int verbosity)
{
- const struct ofp_queue_stats *qs = ofputil_stats_body(oh);
- size_t n = ofputil_stats_body_len(oh) / sizeof *qs;
+ struct ofp_queue_stats *qs;
+ struct ofpbuf b;
+ size_t n;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ ofpraw_pull_assert(&b);
+
+ n = b.size / sizeof *qs;
ds_put_format(string, " %zu queues\n", n);
if (verbosity < 1) {
return;
}
- for (; n--; qs++) {
+ for (;;) {
+ qs = ofpbuf_try_pull(&b, sizeof *qs);
+ if (!qs) {
+ return;
+ }
+
ds_put_cstr(string, " port ");
ofputil_format_port(ntohs(qs->port_no), string);
ds_put_cstr(string, " queue ");
struct ofpbuf b;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
- ofpbuf_pull(&b, sizeof(struct ofp_stats_msg));
+ ofpraw_pull_assert(&b);
ds_put_char(string, '\n');
ofp_print_phy_ports(string, oh->version, &b);
}
static void
ofp_print_stats_request(struct ds *string, const struct ofp_header *oh)
{
- const struct ofp_stats_msg *srq = (const struct ofp_stats_msg *) oh;
+ uint16_t flags = ofpmp_flags(oh);
- if (srq->flags) {
- ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***",
- ntohs(srq->flags));
+ if (flags) {
+ ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
}
}
static void
ofp_print_stats_reply(struct ds *string, const struct ofp_header *oh)
{
- const struct ofp_stats_msg *srp = (const struct ofp_stats_msg *) oh;
-
- if (srp->flags) {
- uint16_t flags = ntohs(srp->flags);
+ uint16_t flags = ofpmp_flags(oh);
+ if (flags) {
ds_put_cstr(string, " flags=");
if (flags & OFPSF_REPLY_MORE) {
ds_put_cstr(string, "[more]");
}
static void
-ofp_header_to_string__(const struct ofp_header *oh,
- const struct ofputil_msg_type *type, struct ds *string)
+ofp_header_to_string__(const struct ofp_header *oh, enum ofpraw raw,
+ struct ds *string)
{
- ds_put_cstr(string, ofputil_msg_type_name(type));
+ ds_put_cstr(string, ofpraw_get_name(raw));
ofp_print_version(oh, string);
}
static void
-ofp_to_string__(const struct ofp_header *oh,
- const struct ofputil_msg_type *type, struct ds *string,
- int verbosity)
+ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
+ struct ds *string, int verbosity)
{
- enum ofputil_msg_code code;
const void *msg = oh;
- ofp_header_to_string__(oh, type, string);
- code = ofputil_msg_type_code(type);
- switch (code) {
- case OFPUTIL_MSG_INVALID:
- break;
-
- case OFPUTIL_OFPT_HELLO:
+ ofp_header_to_string__(oh, raw, string);
+ switch (ofptype_from_ofpraw(raw)) {
+ case OFPTYPE_HELLO:
ds_put_char(string, '\n');
ds_put_hex_dump(string, oh + 1, ntohs(oh->length) - sizeof *oh,
0, true);
break;
- case OFPUTIL_OFPT_ERROR:
- ofp_print_error_msg(string, msg);
+ case OFPTYPE_ERROR:
+ ofp_print_error_msg(string, oh);
break;
- case OFPUTIL_OFPT_ECHO_REQUEST:
- case OFPUTIL_OFPT_ECHO_REPLY:
+ case OFPTYPE_ECHO_REQUEST:
+ case OFPTYPE_ECHO_REPLY:
ofp_print_echo(string, oh, verbosity);
break;
- case OFPUTIL_OFPT_FEATURES_REQUEST:
- break;
-
- case OFPUTIL_OFPT_FEATURES_REPLY:
- ofp_print_switch_features(string, msg);
+ case OFPTYPE_FEATURES_REQUEST:
break;
- case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
+ case OFPTYPE_FEATURES_REPLY:
+ ofp_print_switch_features(string, oh);
break;
- case OFPUTIL_OFPT_GET_CONFIG_REPLY:
- case OFPUTIL_OFPT_SET_CONFIG:
- ofp_print_switch_config(string, msg);
+ case OFPTYPE_GET_CONFIG_REQUEST:
break;
- case OFPUTIL_OFPT_PACKET_IN:
- case OFPUTIL_NXT_PACKET_IN:
- ofp_print_packet_in(string, msg, verbosity);
+ case OFPTYPE_GET_CONFIG_REPLY:
+ case OFPTYPE_SET_CONFIG:
+ ofp_print_switch_config(string, ofpmsg_body(oh));
break;
- case OFPUTIL_OFPT_FLOW_REMOVED:
- case OFPUTIL_NXT_FLOW_REMOVED:
- ofp_print_flow_removed(string, msg);
+ case OFPTYPE_PACKET_IN:
+ ofp_print_packet_in(string, oh, verbosity);
break;
- case OFPUTIL_OFPT_PORT_STATUS:
- ofp_print_port_status(string, msg);
+ case OFPTYPE_FLOW_REMOVED:
+ ofp_print_flow_removed(string, oh);
break;
- case OFPUTIL_OFPT_PACKET_OUT:
- ofp_print_packet_out(string, msg, verbosity);
+ case OFPTYPE_PORT_STATUS:
+ ofp_print_port_status(string, oh);
break;
- case OFPUTIL_OFPT_FLOW_MOD:
- case OFPUTIL_NXT_FLOW_MOD:
- ofp_print_flow_mod(string, msg, code, verbosity);
+ case OFPTYPE_PACKET_OUT:
+ ofp_print_packet_out(string, oh, verbosity);
break;
- case OFPUTIL_OFPT_PORT_MOD:
- ofp_print_port_mod(string, msg);
+ case OFPTYPE_FLOW_MOD:
+ ofp_print_flow_mod(string, oh, verbosity);
break;
- case OFPUTIL_OFPT_BARRIER_REQUEST:
- case OFPUTIL_OFPT_BARRIER_REPLY:
+ case OFPTYPE_PORT_MOD:
+ ofp_print_port_mod(string, oh);
break;
- case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
- case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
- /* XXX */
+ case OFPTYPE_BARRIER_REQUEST:
+ case OFPTYPE_BARRIER_REPLY:
break;
- case OFPUTIL_OFPST_DESC_REQUEST:
- case OFPUTIL_OFPST_PORT_DESC_REQUEST:
+ case OFPTYPE_DESC_STATS_REQUEST:
+ case OFPTYPE_PORT_DESC_STATS_REQUEST:
ofp_print_stats_request(string, oh);
break;
- case OFPUTIL_OFPST_FLOW_REQUEST:
- case OFPUTIL_NXST_FLOW_REQUEST:
- case OFPUTIL_OFPST_AGGREGATE_REQUEST:
- case OFPUTIL_NXST_AGGREGATE_REQUEST:
+ case OFPTYPE_FLOW_STATS_REQUEST:
+ case OFPTYPE_AGGREGATE_STATS_REQUEST:
ofp_print_stats_request(string, oh);
- ofp_print_flow_stats_request(string, msg);
+ ofp_print_flow_stats_request(string, oh);
break;
- case OFPUTIL_OFPST_TABLE_REQUEST:
+ case OFPTYPE_TABLE_STATS_REQUEST:
ofp_print_stats_request(string, oh);
break;
- case OFPUTIL_OFPST_PORT_REQUEST:
+ case OFPTYPE_PORT_STATS_REQUEST:
ofp_print_stats_request(string, oh);
- ofp_print_ofpst_port_request(string, msg);
+ ofp_print_ofpst_port_request(string, oh);
break;
- case OFPUTIL_OFPST_QUEUE_REQUEST:
+ case OFPTYPE_QUEUE_STATS_REQUEST:
ofp_print_stats_request(string, oh);
- ofp_print_ofpst_queue_request(string, msg);
+ ofp_print_ofpst_queue_request(string, oh);
break;
- case OFPUTIL_OFPST_DESC_REPLY:
+ case OFPTYPE_DESC_STATS_REPLY:
ofp_print_stats_reply(string, oh);
- ofp_print_ofpst_desc_reply(string, msg);
+ ofp_print_ofpst_desc_reply(string, oh);
break;
- case OFPUTIL_OFPST_FLOW_REPLY:
- case OFPUTIL_NXST_FLOW_REPLY:
+ case OFPTYPE_FLOW_STATS_REPLY:
ofp_print_stats_reply(string, oh);
ofp_print_flow_stats_reply(string, oh);
break;
- case OFPUTIL_OFPST_QUEUE_REPLY:
+ case OFPTYPE_QUEUE_STATS_REPLY:
ofp_print_stats_reply(string, oh);
ofp_print_ofpst_queue_reply(string, oh, verbosity);
break;
- case OFPUTIL_OFPST_PORT_REPLY:
+ case OFPTYPE_PORT_STATS_REPLY:
ofp_print_stats_reply(string, oh);
ofp_print_ofpst_port_reply(string, oh, verbosity);
break;
- case OFPUTIL_OFPST_TABLE_REPLY:
+ case OFPTYPE_TABLE_STATS_REPLY:
ofp_print_stats_reply(string, oh);
ofp_print_ofpst_table_reply(string, oh, verbosity);
break;
- case OFPUTIL_OFPST_AGGREGATE_REPLY:
+ case OFPTYPE_AGGREGATE_STATS_REPLY:
ofp_print_stats_reply(string, oh);
- ofp_print_ofpst_aggregate_reply(string, msg);
+ ofp_print_aggregate_stats_reply(string, oh);
break;
- case OFPUTIL_OFPST_PORT_DESC_REPLY:
+ case OFPTYPE_PORT_DESC_STATS_REPLY:
ofp_print_stats_reply(string, oh);
ofp_print_ofpst_port_desc_reply(string, oh);
break;
- case OFPUTIL_NXT_ROLE_REQUEST:
- case OFPUTIL_NXT_ROLE_REPLY:
- ofp_print_nxt_role_message(string, msg);
+ case OFPTYPE_ROLE_REQUEST:
+ case OFPTYPE_ROLE_REPLY:
+ ofp_print_nxt_role_message(string, ofpmsg_body(oh));
break;
- case OFPUTIL_NXT_FLOW_MOD_TABLE_ID:
- ofp_print_nxt_flow_mod_table_id(string, msg);
+ case OFPTYPE_FLOW_MOD_TABLE_ID:
+ ofp_print_nxt_flow_mod_table_id(string, ofpmsg_body(oh));
break;
- case OFPUTIL_NXT_SET_FLOW_FORMAT:
- ofp_print_nxt_set_flow_format(string, msg);
+ case OFPTYPE_SET_FLOW_FORMAT:
+ ofp_print_nxt_set_flow_format(string, ofpmsg_body(oh));
break;
- case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
- ofp_print_nxt_set_packet_in_format(string, msg);
+ case OFPTYPE_SET_PACKET_IN_FORMAT:
+ ofp_print_nxt_set_packet_in_format(string, ofpmsg_body(oh));
break;
- case OFPUTIL_NXT_FLOW_AGE:
+ case OFPTYPE_FLOW_AGE:
break;
- case OFPUTIL_NXT_SET_CONTROLLER_ID:
- ofp_print_nxt_set_controller_id(string, msg);
+ case OFPTYPE_SET_CONTROLLER_ID:
+ ofp_print_nxt_set_controller_id(string, ofpmsg_body(oh));
break;
- case OFPUTIL_NXT_SET_ASYNC_CONFIG:
- ofp_print_nxt_set_async_config(string, msg);
- break;
-
- case OFPUTIL_NXST_AGGREGATE_REPLY:
- ofp_print_stats_reply(string, oh);
- ofp_print_nxst_aggregate_reply(string, msg);
+ case OFPTYPE_SET_ASYNC_CONFIG:
+ ofp_print_nxt_set_async_config(string, ofpmsg_body(oh));
break;
- case OFPUTIL_NXT_FLOW_MONITOR_CANCEL:
+ case OFPTYPE_FLOW_MONITOR_CANCEL:
ofp_print_nxt_flow_monitor_cancel(string, msg);
break;
- case OFPUTIL_NXT_FLOW_MONITOR_PAUSED:
- case OFPUTIL_NXT_FLOW_MONITOR_RESUMED:
+ case OFPTYPE_FLOW_MONITOR_PAUSED:
+ case OFPTYPE_FLOW_MONITOR_RESUMED:
break;
- case OFPUTIL_NXST_FLOW_MONITOR_REQUEST:
+ case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
ofp_print_nxst_flow_monitor_request(string, msg);
break;
- case OFPUTIL_NXST_FLOW_MONITOR_REPLY:
+ case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
ofp_print_nxst_flow_monitor_reply(string, msg);
break;
}
ds_put_format(&string, "OpenFlow packet too short (only %zu bytes):\n",
len);
} else if (ntohs(oh->length) > len) {
- const struct ofputil_msg_type *type;
enum ofperr error;
+ enum ofpraw raw;
- error = ofputil_decode_msg_type_partial(oh, len, &type);
+ error = ofpraw_decode_partial(&raw, oh, len);
if (!error) {
- ofp_header_to_string__(oh, type, &string);
+ ofp_header_to_string__(oh, raw, &string);
ds_put_char(&string, '\n');
}
"(***only uses %"PRIu16" bytes out of %zu***)\n",
ntohs(oh->length), len);
} else {
- const struct ofputil_msg_type *type;
enum ofperr error;
+ enum ofpraw raw;
- error = ofputil_decode_msg_type(oh, &type);
+ error = ofpraw_decode(&raw, oh);
if (!error) {
- ofp_to_string__(oh, type, &string, verbosity);
+ ofp_to_string__(oh, raw, &string, verbosity);
if (verbosity >= 5) {
if (ds_last(&string) != '\n') {
ds_put_char(&string, '\n');
#include "nx-match.h"
#include "ofp-actions.h"
#include "ofp-errors.h"
+#include "ofp-msgs.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "packets.h"
? htons(FLOW_DL_TYPE_NONE)
: ofp_dl_type);
}
-
-/* Returns a transaction ID to use for an outgoing OpenFlow message. */
-static ovs_be32
-alloc_xid(void)
-{
- static uint32_t next_xid = 1;
- return htonl(next_xid++);
-}
-\f
-/* Basic parsing of OpenFlow messages. */
-
-struct ofputil_msg_type {
- enum ofputil_msg_code code; /* OFPUTIL_*. */
- uint8_t ofp_version; /* An OpenFlow version or 0 for "any". */
- uint32_t value; /* OFPT_*, OFPST_*, NXT_*, or NXST_*. */
- const char *name; /* e.g. "OFPT_FLOW_REMOVED". */
- unsigned int min_size; /* Minimum total message size in bytes. */
- /* 0 if 'min_size' is the exact size that the message must be. Otherwise,
- * the message may exceed 'min_size' by an even multiple of this value. */
- unsigned int extra_multiple;
-};
-
-/* Represents a malformed OpenFlow message. */
-static const struct ofputil_msg_type ofputil_invalid_type = {
- OFPUTIL_MSG_INVALID, 0, 0, "OFPUTIL_MSG_INVALID", 0, 0
-};
-
-struct ofputil_msg_category {
- const char *name; /* e.g. "OpenFlow message" */
- const struct ofputil_msg_type *types;
- size_t n_types;
- enum ofperr missing_error; /* Error value for missing type. */
-};
-
-static enum ofperr
-ofputil_check_length(const struct ofputil_msg_type *type, unsigned int size)
-{
- switch (type->extra_multiple) {
- case 0:
- if (size != type->min_size) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect "
- "length %u (expected length %u)",
- type->name, size, type->min_size);
- return OFPERR_OFPBRC_BAD_LEN;
- }
- return 0;
-
- case 1:
- if (size < type->min_size) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect "
- "length %u (expected length at least %u bytes)",
- type->name, size, type->min_size);
- return OFPERR_OFPBRC_BAD_LEN;
- }
- return 0;
-
- default:
- if (size < type->min_size
- || (size - type->min_size) % type->extra_multiple) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect "
- "length %u (must be exactly %u bytes or longer "
- "by an integer multiple of %u bytes)",
- type->name, size,
- type->min_size, type->extra_multiple);
- return OFPERR_OFPBRC_BAD_LEN;
- }
- return 0;
- }
-}
-
-static enum ofperr
-ofputil_lookup_openflow_message(const struct ofputil_msg_category *cat,
- uint8_t version, uint32_t value,
- const struct ofputil_msg_type **typep)
-{
- const struct ofputil_msg_type *type;
-
- for (type = cat->types; type < &cat->types[cat->n_types]; type++) {
- if (type->value == value
- && (!type->ofp_version || version == type->ofp_version)) {
- *typep = type;
- return 0;
- }
- }
-
- VLOG_WARN_RL(&bad_ofmsg_rl, "received %s of unknown type %"PRIu32,
- cat->name, value);
- return cat->missing_error;
-}
-
-static enum ofperr
-ofputil_decode_vendor(const struct ofp_header *oh, size_t length,
- const struct ofputil_msg_type **typep)
-{
- static const struct ofputil_msg_type nxt_messages[] = {
- { OFPUTIL_NXT_ROLE_REQUEST, OFP10_VERSION,
- NXT_ROLE_REQUEST, "NXT_ROLE_REQUEST",
- sizeof(struct nx_role_request), 0 },
-
- { OFPUTIL_NXT_ROLE_REPLY, OFP10_VERSION,
- NXT_ROLE_REPLY, "NXT_ROLE_REPLY",
- sizeof(struct nx_role_request), 0 },
-
- { OFPUTIL_NXT_SET_FLOW_FORMAT, OFP10_VERSION,
- NXT_SET_FLOW_FORMAT, "NXT_SET_FLOW_FORMAT",
- sizeof(struct nx_set_flow_format), 0 },
-
- { OFPUTIL_NXT_SET_PACKET_IN_FORMAT, OFP10_VERSION,
- NXT_SET_PACKET_IN_FORMAT, "NXT_SET_PACKET_IN_FORMAT",
- sizeof(struct nx_set_packet_in_format), 0 },
-
- { OFPUTIL_NXT_PACKET_IN, OFP10_VERSION,
- NXT_PACKET_IN, "NXT_PACKET_IN",
- sizeof(struct nx_packet_in), 1 },
-
- { OFPUTIL_NXT_FLOW_MOD, OFP10_VERSION,
- NXT_FLOW_MOD, "NXT_FLOW_MOD",
- sizeof(struct nx_flow_mod), 8 },
-
- { OFPUTIL_NXT_FLOW_REMOVED, OFP10_VERSION,
- NXT_FLOW_REMOVED, "NXT_FLOW_REMOVED",
- sizeof(struct nx_flow_removed), 8 },
-
- { OFPUTIL_NXT_FLOW_MOD_TABLE_ID, OFP10_VERSION,
- NXT_FLOW_MOD_TABLE_ID, "NXT_FLOW_MOD_TABLE_ID",
- sizeof(struct nx_flow_mod_table_id), 0 },
-
- { OFPUTIL_NXT_FLOW_AGE, OFP10_VERSION,
- NXT_FLOW_AGE, "NXT_FLOW_AGE",
- sizeof(struct nicira_header), 0 },
-
- { OFPUTIL_NXT_SET_ASYNC_CONFIG, OFP10_VERSION,
- NXT_SET_ASYNC_CONFIG, "NXT_SET_ASYNC_CONFIG",
- sizeof(struct nx_async_config), 0 },
-
- { OFPUTIL_NXT_SET_CONTROLLER_ID, OFP10_VERSION,
- NXT_SET_CONTROLLER_ID, "NXT_SET_CONTROLLER_ID",
- sizeof(struct nx_controller_id), 0 },
-
- { OFPUTIL_NXT_FLOW_MONITOR_CANCEL, OFP10_VERSION,
- NXT_FLOW_MONITOR_CANCEL, "NXT_FLOW_MONITOR_CANCEL",
- sizeof(struct nx_flow_monitor_cancel), 0 },
-
- { OFPUTIL_NXT_FLOW_MONITOR_PAUSED, OFP10_VERSION,
- NXT_FLOW_MONITOR_PAUSED, "NXT_FLOW_MONITOR_PAUSED",
- sizeof(struct nicira_header), 0 },
-
- { OFPUTIL_NXT_FLOW_MONITOR_RESUMED, OFP10_VERSION,
- NXT_FLOW_MONITOR_RESUMED, "NXT_FLOW_MONITOR_RESUMED",
- sizeof(struct nicira_header), 0 },
- };
-
- static const struct ofputil_msg_category nxt_category = {
- "Nicira extension message",
- nxt_messages, ARRAY_SIZE(nxt_messages),
- OFPERR_OFPBRC_BAD_SUBTYPE
- };
-
- const struct ofp_vendor_header *ovh;
- const struct nicira_header *nh;
-
- if (length < sizeof(struct ofp_vendor_header)) {
- if (length == ntohs(oh->length)) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "truncated vendor message");
- }
- return OFPERR_OFPBRC_BAD_LEN;
- }
-
- ovh = (const struct ofp_vendor_header *) oh;
- if (ovh->vendor != htonl(NX_VENDOR_ID)) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "received vendor message for unknown "
- "vendor %"PRIx32, ntohl(ovh->vendor));
- return OFPERR_OFPBRC_BAD_VENDOR;
- }
-
- if (length < sizeof(struct nicira_header)) {
- if (length == ntohs(oh->length)) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "received Nicira vendor message of "
- "length %u (expected at least %zu)",
- ntohs(ovh->header.length),
- sizeof(struct nicira_header));
- }
- return OFPERR_OFPBRC_BAD_LEN;
- }
-
- nh = (const struct nicira_header *) oh;
- return ofputil_lookup_openflow_message(&nxt_category, oh->version,
- ntohl(nh->subtype), typep);
-}
-
-static enum ofperr
-check_nxstats_msg(const struct ofp_header *oh, size_t length)
-{
- const struct ofp_stats_msg *osm = (const struct ofp_stats_msg *) oh;
- ovs_be32 vendor;
-
- if (length < sizeof(struct ofp_vendor_stats_msg)) {
- if (length == ntohs(oh->length)) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "truncated vendor stats message");
- }
- return OFPERR_OFPBRC_BAD_LEN;
- }
-
- memcpy(&vendor, osm + 1, sizeof vendor);
- if (vendor != htonl(NX_VENDOR_ID)) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "received vendor stats message for "
- "unknown vendor %"PRIx32, ntohl(vendor));
- return OFPERR_OFPBRC_BAD_VENDOR;
- }
-
- if (length < sizeof(struct nicira_stats_msg)) {
- if (length == ntohs(osm->header.length)) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "truncated Nicira stats message");
- }
- return OFPERR_OFPBRC_BAD_LEN;
- }
-
- return 0;
-}
-
-static enum ofperr
-ofputil_decode_nxst_request(const struct ofp_header *oh, size_t length,
- const struct ofputil_msg_type **typep)
-{
- static const struct ofputil_msg_type nxst_requests[] = {
- { OFPUTIL_NXST_FLOW_REQUEST, OFP10_VERSION,
- NXST_FLOW, "NXST_FLOW request",
- sizeof(struct nx_flow_stats_request), 8 },
-
- { OFPUTIL_NXST_AGGREGATE_REQUEST, OFP10_VERSION,
- NXST_AGGREGATE, "NXST_AGGREGATE request",
- sizeof(struct nx_aggregate_stats_request), 8 },
-
- { OFPUTIL_NXST_FLOW_MONITOR_REQUEST, OFP10_VERSION,
- NXST_FLOW_MONITOR, "NXST_FLOW_MONITOR request",
- sizeof(struct nicira_stats_msg), 8 },
- };
-
- static const struct ofputil_msg_category nxst_request_category = {
- "Nicira extension statistics request",
- nxst_requests, ARRAY_SIZE(nxst_requests),
- OFPERR_OFPBRC_BAD_SUBTYPE
- };
-
- const struct nicira_stats_msg *nsm;
- enum ofperr error;
-
- error = check_nxstats_msg(oh, length);
- if (error) {
- return error;
- }
-
- nsm = (struct nicira_stats_msg *) oh;
- return ofputil_lookup_openflow_message(&nxst_request_category, oh->version,
- ntohl(nsm->subtype), typep);
-}
-
-static enum ofperr
-ofputil_decode_nxst_reply(const struct ofp_header *oh, size_t length,
- const struct ofputil_msg_type **typep)
-{
- static const struct ofputil_msg_type nxst_replies[] = {
- { OFPUTIL_NXST_FLOW_REPLY, OFP10_VERSION,
- NXST_FLOW, "NXST_FLOW reply",
- sizeof(struct nicira_stats_msg), 8 },
-
- { OFPUTIL_NXST_AGGREGATE_REPLY, OFP10_VERSION,
- NXST_AGGREGATE, "NXST_AGGREGATE reply",
- sizeof(struct nx_aggregate_stats_reply), 0 },
-
- { OFPUTIL_NXST_FLOW_MONITOR_REPLY, OFP10_VERSION,
- NXST_FLOW_MONITOR, "NXST_FLOW_MONITOR reply",
- sizeof(struct nicira_stats_msg), 8 },
- };
-
- static const struct ofputil_msg_category nxst_reply_category = {
- "Nicira extension statistics reply",
- nxst_replies, ARRAY_SIZE(nxst_replies),
- OFPERR_OFPBRC_BAD_SUBTYPE
- };
-
- const struct nicira_stats_msg *nsm;
- enum ofperr error;
-
- error = check_nxstats_msg(oh, length);
- if (error) {
- return error;
- }
-
- nsm = (struct nicira_stats_msg *) oh;
- return ofputil_lookup_openflow_message(&nxst_reply_category, oh->version,
- ntohl(nsm->subtype), typep);
-}
-
-static enum ofperr
-check_stats_msg(const struct ofp_header *oh, size_t length)
-{
- if (length < sizeof(struct ofp_stats_msg)) {
- if (length == ntohs(oh->length)) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "truncated stats message");
- }
- return OFPERR_OFPBRC_BAD_LEN;
- }
-
- return 0;
-}
-
-static enum ofperr
-ofputil_decode_ofpst_request(const struct ofp_header *oh, size_t length,
- const struct ofputil_msg_type **typep)
-{
- static const struct ofputil_msg_type ofpst_requests[] = {
- { OFPUTIL_OFPST_DESC_REQUEST, OFP10_VERSION,
- OFPST_DESC, "OFPST_DESC request",
- sizeof(struct ofp_stats_msg), 0 },
-
- { OFPUTIL_OFPST_FLOW_REQUEST, OFP10_VERSION,
- OFPST_FLOW, "OFPST_FLOW request",
- sizeof(struct ofp_flow_stats_request), 0 },
-
- { OFPUTIL_OFPST_AGGREGATE_REQUEST, OFP10_VERSION,
- OFPST_AGGREGATE, "OFPST_AGGREGATE request",
- sizeof(struct ofp_flow_stats_request), 0 },
-
- { OFPUTIL_OFPST_TABLE_REQUEST, OFP10_VERSION,
- OFPST_TABLE, "OFPST_TABLE request",
- sizeof(struct ofp_stats_msg), 0 },
-
- { OFPUTIL_OFPST_PORT_REQUEST, OFP10_VERSION,
- OFPST_PORT, "OFPST_PORT request",
- sizeof(struct ofp_port_stats_request), 0 },
-
- { OFPUTIL_OFPST_QUEUE_REQUEST, OFP10_VERSION,
- OFPST_QUEUE, "OFPST_QUEUE request",
- sizeof(struct ofp_queue_stats_request), 0 },
-
- { OFPUTIL_OFPST_PORT_DESC_REQUEST, OFP10_VERSION,
- OFPST_PORT_DESC, "OFPST_PORT_DESC request",
- sizeof(struct ofp_stats_msg), 0 },
-
- { 0, 0,
- OFPST_VENDOR, "OFPST_VENDOR request",
- sizeof(struct ofp_vendor_stats_msg), 1 },
- };
-
- static const struct ofputil_msg_category ofpst_request_category = {
- "OpenFlow statistics",
- ofpst_requests, ARRAY_SIZE(ofpst_requests),
- OFPERR_OFPBRC_BAD_STAT
- };
-
- const struct ofp_stats_msg *request = (const struct ofp_stats_msg *) oh;
- enum ofperr error;
-
- error = check_stats_msg(oh, length);
- if (error) {
- return error;
- }
-
- error = ofputil_lookup_openflow_message(&ofpst_request_category,
- oh->version, ntohs(request->type),
- typep);
- if (!error && request->type == htons(OFPST_VENDOR)) {
- error = ofputil_decode_nxst_request(oh, length, typep);
- }
- return error;
-}
-
-static enum ofperr
-ofputil_decode_ofpst_reply(const struct ofp_header *oh, size_t length,
- const struct ofputil_msg_type **typep)
-{
- static const struct ofputil_msg_type ofpst_replies[] = {
- { OFPUTIL_OFPST_DESC_REPLY, OFP10_VERSION,
- OFPST_DESC, "OFPST_DESC reply",
- sizeof(struct ofp_desc_stats), 0 },
-
- { OFPUTIL_OFPST_FLOW_REPLY, OFP10_VERSION,
- OFPST_FLOW, "OFPST_FLOW reply",
- sizeof(struct ofp_stats_msg), 1 },
-
- { OFPUTIL_OFPST_AGGREGATE_REPLY, OFP10_VERSION,
- OFPST_AGGREGATE, "OFPST_AGGREGATE reply",
- sizeof(struct ofp_aggregate_stats_reply), 0 },
-
- { OFPUTIL_OFPST_TABLE_REPLY, OFP10_VERSION,
- OFPST_TABLE, "OFPST_TABLE reply",
- sizeof(struct ofp_stats_msg), sizeof(struct ofp_table_stats) },
-
- { OFPUTIL_OFPST_PORT_REPLY, OFP10_VERSION,
- OFPST_PORT, "OFPST_PORT reply",
- sizeof(struct ofp_stats_msg), sizeof(struct ofp_port_stats) },
-
- { OFPUTIL_OFPST_QUEUE_REPLY, OFP10_VERSION,
- OFPST_QUEUE, "OFPST_QUEUE reply",
- sizeof(struct ofp_stats_msg), sizeof(struct ofp_queue_stats) },
-
- { OFPUTIL_OFPST_PORT_DESC_REPLY, OFP10_VERSION,
- OFPST_PORT_DESC, "OFPST_PORT_DESC reply",
- sizeof(struct ofp_stats_msg), sizeof(struct ofp10_phy_port) },
-
- { 0, 0,
- OFPST_VENDOR, "OFPST_VENDOR reply",
- sizeof(struct ofp_vendor_stats_msg), 1 },
- };
-
- static const struct ofputil_msg_category ofpst_reply_category = {
- "OpenFlow statistics",
- ofpst_replies, ARRAY_SIZE(ofpst_replies),
- OFPERR_OFPBRC_BAD_STAT
- };
-
- const struct ofp_stats_msg *reply = (const struct ofp_stats_msg *) oh;
- enum ofperr error;
-
- error = check_stats_msg(oh, length);
- if (error) {
- return error;
- }
-
- error = ofputil_lookup_openflow_message(&ofpst_reply_category, oh->version,
- ntohs(reply->type), typep);
- if (!error && reply->type == htons(OFPST_VENDOR)) {
- error = ofputil_decode_nxst_reply(oh, length, typep);
- }
- return error;
-}
-
-static enum ofperr
-ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
- const struct ofputil_msg_type **typep)
-{
- static const struct ofputil_msg_type ofpt_messages[] = {
- { OFPUTIL_OFPT_HELLO, OFP10_VERSION,
- OFPT_HELLO, "OFPT_HELLO",
- sizeof(struct ofp_hello), 1 },
-
- { OFPUTIL_OFPT_ERROR, 0,
- OFPT_ERROR, "OFPT_ERROR",
- sizeof(struct ofp_error_msg), 1 },
-
- { OFPUTIL_OFPT_ECHO_REQUEST, OFP10_VERSION,
- OFPT_ECHO_REQUEST, "OFPT_ECHO_REQUEST",
- sizeof(struct ofp_header), 1 },
-
- { OFPUTIL_OFPT_ECHO_REPLY, OFP10_VERSION,
- OFPT_ECHO_REPLY, "OFPT_ECHO_REPLY",
- sizeof(struct ofp_header), 1 },
-
- { OFPUTIL_OFPT_FEATURES_REQUEST, OFP10_VERSION,
- OFPT_FEATURES_REQUEST, "OFPT_FEATURES_REQUEST",
- sizeof(struct ofp_header), 0 },
-
- { OFPUTIL_OFPT_FEATURES_REPLY, OFP10_VERSION,
- OFPT_FEATURES_REPLY, "OFPT_FEATURES_REPLY",
- sizeof(struct ofp_switch_features), sizeof(struct ofp10_phy_port) },
- { OFPUTIL_OFPT_FEATURES_REPLY, OFP11_VERSION,
- OFPT_FEATURES_REPLY, "OFPT_FEATURES_REPLY",
- sizeof(struct ofp_switch_features), sizeof(struct ofp11_port) },
-
- { OFPUTIL_OFPT_GET_CONFIG_REQUEST, OFP10_VERSION,
- OFPT_GET_CONFIG_REQUEST, "OFPT_GET_CONFIG_REQUEST",
- sizeof(struct ofp_header), 0 },
-
- { OFPUTIL_OFPT_GET_CONFIG_REPLY, OFP10_VERSION,
- OFPT_GET_CONFIG_REPLY, "OFPT_GET_CONFIG_REPLY",
- sizeof(struct ofp_switch_config), 0 },
-
- { OFPUTIL_OFPT_SET_CONFIG, OFP10_VERSION,
- OFPT_SET_CONFIG, "OFPT_SET_CONFIG",
- sizeof(struct ofp_switch_config), 0 },
-
- { OFPUTIL_OFPT_PACKET_IN, OFP10_VERSION,
- OFPT_PACKET_IN, "OFPT_PACKET_IN",
- offsetof(struct ofp_packet_in, data), 1 },
-
- { OFPUTIL_OFPT_FLOW_REMOVED, OFP10_VERSION,
- OFPT_FLOW_REMOVED, "OFPT_FLOW_REMOVED",
- sizeof(struct ofp_flow_removed), 0 },
-
- { OFPUTIL_OFPT_PORT_STATUS, OFP10_VERSION,
- OFPT_PORT_STATUS, "OFPT_PORT_STATUS",
- sizeof(struct ofp_port_status) + sizeof(struct ofp10_phy_port), 0 },
- { OFPUTIL_OFPT_PORT_STATUS, OFP11_VERSION,
- OFPT_PORT_STATUS, "OFPT_PORT_STATUS",
- sizeof(struct ofp_port_status) + sizeof(struct ofp11_port), 0 },
-
- { OFPUTIL_OFPT_PACKET_OUT, OFP10_VERSION,
- OFPT_PACKET_OUT, "OFPT_PACKET_OUT",
- sizeof(struct ofp_packet_out), 1 },
-
- { OFPUTIL_OFPT_FLOW_MOD, OFP10_VERSION,
- OFPT_FLOW_MOD, "OFPT_FLOW_MOD",
- sizeof(struct ofp_flow_mod), 1 },
-
- { OFPUTIL_OFPT_PORT_MOD, OFP10_VERSION,
- OFPT10_PORT_MOD, "OFPT_PORT_MOD",
- sizeof(struct ofp10_port_mod), 0 },
- { OFPUTIL_OFPT_PORT_MOD, OFP11_VERSION,
- OFPT11_PORT_MOD, "OFPT_PORT_MOD",
- sizeof(struct ofp11_port_mod), 0 },
-
- { 0, OFP10_VERSION,
- OFPT10_STATS_REQUEST, "OFPT_STATS_REQUEST",
- sizeof(struct ofp_stats_msg), 1 },
-
- { 0, OFP10_VERSION,
- OFPT10_STATS_REPLY, "OFPT_STATS_REPLY",
- sizeof(struct ofp_stats_msg), 1 },
-
- { OFPUTIL_OFPT_BARRIER_REQUEST, OFP10_VERSION,
- OFPT10_BARRIER_REQUEST, "OFPT_BARRIER_REQUEST",
- sizeof(struct ofp_header), 0 },
-
- { OFPUTIL_OFPT_BARRIER_REPLY, OFP10_VERSION,
- OFPT10_BARRIER_REPLY, "OFPT_BARRIER_REPLY",
- sizeof(struct ofp_header), 0 },
-
- { 0, 0,
- OFPT_VENDOR, "OFPT_VENDOR",
- sizeof(struct ofp_vendor_header), 1 },
- };
-
- static const struct ofputil_msg_category ofpt_category = {
- "OpenFlow message",
- ofpt_messages, ARRAY_SIZE(ofpt_messages),
- OFPERR_OFPBRC_BAD_TYPE
- };
-
- enum ofperr error;
-
- error = ofputil_lookup_openflow_message(&ofpt_category, oh->version,
- oh->type, typep);
- if (!error) {
- switch ((oh->version << 8) | oh->type) {
- case (OFP10_VERSION << 8) | OFPT_VENDOR:
- case (OFP11_VERSION << 8) | OFPT_VENDOR:
- error = ofputil_decode_vendor(oh, length, typep);
- break;
-
- case (OFP10_VERSION << 8) | OFPT10_STATS_REQUEST:
- case (OFP11_VERSION << 8) | OFPT11_STATS_REQUEST:
- error = ofputil_decode_ofpst_request(oh, length, typep);
- break;
-
- case (OFP10_VERSION << 8) | OFPT10_STATS_REPLY:
- case (OFP11_VERSION << 8) | OFPT11_STATS_REPLY:
- error = ofputil_decode_ofpst_reply(oh, length, typep);
-
- default:
- break;
- }
- }
- return error;
-}
-
-/* Decodes the message type represented by 'oh'. Returns 0 if successful or an
- * OpenFlow error code on failure. Either way, stores in '*typep' a type
- * structure that can be inspected with the ofputil_msg_type_*() functions.
- *
- * oh->length must indicate the correct length of the message (and must be at
- * least sizeof(struct ofp_header)).
- *
- * Success indicates that 'oh' is at least as long as the minimum-length
- * message of its type. */
-enum ofperr
-ofputil_decode_msg_type(const struct ofp_header *oh,
- const struct ofputil_msg_type **typep)
-{
- size_t length = ntohs(oh->length);
- enum ofperr error;
-
- error = ofputil_decode_msg_type__(oh, length, typep);
- if (!error) {
- error = ofputil_check_length(*typep, length);
- }
- if (error) {
- *typep = &ofputil_invalid_type;
- }
- return error;
-}
-
-/* Decodes the message type represented by 'oh', of which only the first
- * 'length' bytes are available. Returns 0 if successful or an OpenFlow error
- * code on failure. Either way, stores in '*typep' a type structure that can
- * be inspected with the ofputil_msg_type_*() functions. */
-enum ofperr
-ofputil_decode_msg_type_partial(const struct ofp_header *oh, size_t length,
- const struct ofputil_msg_type **typep)
-{
- enum ofperr error;
-
- error = (length >= sizeof *oh
- ? ofputil_decode_msg_type__(oh, length, typep)
- : OFPERR_OFPBRC_BAD_LEN);
- if (error) {
- *typep = &ofputil_invalid_type;
- }
- return error;
-}
-
-/* Returns an OFPUTIL_* message type code for 'type'. */
-enum ofputil_msg_code
-ofputil_msg_type_code(const struct ofputil_msg_type *type)
-{
- return type->code;
-}
\f
/* Protocols. */
assert(ofputil_nx_flow_format_is_valid(nxff));
- sff = make_nxmsg(sizeof *sff, NXT_SET_FLOW_FORMAT, &msg);
+ msg = ofpraw_alloc(OFPRAW_NXT_SET_FLOW_FORMAT, OFP10_VERSION, 0);
+ sff = ofpbuf_put_zeros(msg, sizeof *sff);
sff->format = htonl(nxff);
return msg;
struct nx_set_packet_in_format *spif;
struct ofpbuf *msg;
- spif = make_nxmsg(sizeof *spif, NXT_SET_PACKET_IN_FORMAT, &msg);
+ msg = ofpraw_alloc(OFPRAW_NXT_SET_PACKET_IN_FORMAT, OFP10_VERSION, 0);
+ spif = ofpbuf_put_zeros(msg, sizeof *spif);
spif->format = htonl(packet_in_format);
return msg;
struct nx_flow_mod_table_id *nfmti;
struct ofpbuf *msg;
- nfmti = make_nxmsg(sizeof *nfmti, NXT_FLOW_MOD_TABLE_ID, &msg);
+ msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MOD_TABLE_ID, OFP10_VERSION, 0);
+ nfmti = ofpbuf_put_zeros(msg, sizeof *nfmti);
nfmti->set = flow_mod_table_id;
return msg;
}
enum ofputil_protocol protocol,
struct ofpbuf *ofpacts)
{
- const struct ofputil_msg_type *type;
uint16_t command;
struct ofpbuf b;
+ enum ofpraw raw;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
-
- ofputil_decode_msg_type(oh, &type);
- if (ofputil_msg_type_code(type) == OFPUTIL_OFPT_FLOW_MOD) {
- /* Standard OpenFlow flow_mod. */
+ raw = ofpraw_pull_assert(&b);
+ if (raw == OFPRAW_OFPT10_FLOW_MOD) {
+ /* Standard OpenFlow 1.1 flow_mod. */
const struct ofp_flow_mod *ofm;
uint16_t priority;
enum ofperr error;
fm->buffer_id = ntohl(ofm->buffer_id);
fm->out_port = ntohs(ofm->out_port);
fm->flags = ntohs(ofm->flags);
- } else if (ofputil_msg_type_code(type) == OFPUTIL_NXT_FLOW_MOD) {
+ } else if (raw == OFPRAW_NXT_FLOW_MOD) {
/* Nicira extended flow_mod. */
const struct nx_flow_mod *nfm;
enum ofperr error;
switch (protocol) {
case OFPUTIL_P_OF10:
case OFPUTIL_P_OF10_TID:
- msg = ofpbuf_new(sizeof *ofm + fm->ofpacts_len);
- ofm = put_openflow(sizeof *ofm, OFPT_FLOW_MOD, msg);
+ msg = ofpraw_alloc(OFPRAW_OFPT10_FLOW_MOD, OFP10_VERSION,
+ fm->ofpacts_len);
+ ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
ofputil_cls_rule_to_ofp10_match(&fm->cr, &ofm->match);
ofm->cookie = fm->new_cookie;
ofm->command = htons(command);
case OFPUTIL_P_NXM:
case OFPUTIL_P_NXM_TID:
- msg = ofpbuf_new(sizeof *nfm + NXM_TYPICAL_LEN + fm->ofpacts_len);
- put_nxmsg(sizeof *nfm, NXT_FLOW_MOD, msg);
- nfm = msg->data;
+ msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MOD, OFP10_VERSION,
+ NXM_TYPICAL_LEN + fm->ofpacts_len);
+ nfm = ofpbuf_put_zeros(msg, sizeof *nfm);
nfm->command = htons(command);
nfm->cookie = fm->new_cookie;
match_len = nx_put_match(msg, false, &fm->cr,
fm->cookie, fm->cookie_mask);
- nfm = msg->data;
+ nfm = msg->l3;
nfm->idle_timeout = htons(fm->idle_timeout);
nfm->hard_timeout = htons(fm->hard_timeout);
nfm->priority = htons(fm->cr.priority);
if (fm->ofpacts) {
ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg);
}
- update_openflow_length(msg);
+ ofpmsg_update_length(msg);
return msg;
}
static enum ofperr
ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
- const struct ofp_header *oh,
+ const struct ofp_flow_stats_request *ofsr,
bool aggregate)
{
- const struct ofp_flow_stats_request *ofsr =
- (const struct ofp_flow_stats_request *) oh;
-
fsr->aggregate = aggregate;
ofputil_cls_rule_from_ofp10_match(&ofsr->match, 0, &fsr->match);
fsr->out_port = ntohs(ofsr->out_port);
static enum ofperr
ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
- const struct ofp_header *oh,
- bool aggregate)
+ struct ofpbuf *b, bool aggregate)
{
const struct nx_flow_stats_request *nfsr;
- struct ofpbuf b;
enum ofperr error;
- ofpbuf_use_const(&b, oh, ntohs(oh->length));
-
- nfsr = ofpbuf_pull(&b, sizeof *nfsr);
- error = nx_pull_match(&b, ntohs(nfsr->match_len), 0, &fsr->match,
+ nfsr = ofpbuf_pull(b, sizeof *nfsr);
+ error = nx_pull_match(b, ntohs(nfsr->match_len), 0, &fsr->match,
&fsr->cookie, &fsr->cookie_mask);
if (error) {
return error;
}
- if (b.size) {
+ if (b->size) {
return OFPERR_OFPBRC_BAD_LEN;
}
ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr,
const struct ofp_header *oh)
{
- const struct ofputil_msg_type *type;
+ enum ofpraw raw;
struct ofpbuf b;
- int code;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+ switch ((int) raw) {
+ case OFPRAW_OFPST_FLOW_REQUEST:
+ return ofputil_decode_ofpst_flow_request(fsr, b.data, false);
- ofputil_decode_msg_type(oh, &type);
- code = ofputil_msg_type_code(type);
- switch (code) {
- case OFPUTIL_OFPST_FLOW_REQUEST:
- return ofputil_decode_ofpst_flow_request(fsr, oh, false);
-
- case OFPUTIL_OFPST_AGGREGATE_REQUEST:
- return ofputil_decode_ofpst_flow_request(fsr, oh, true);
+ case OFPRAW_OFPST_AGGREGATE_REQUEST:
+ return ofputil_decode_ofpst_flow_request(fsr, b.data, true);
- case OFPUTIL_NXST_FLOW_REQUEST:
- return ofputil_decode_nxst_flow_request(fsr, oh, false);
+ case OFPRAW_NXST_FLOW_REQUEST:
+ return ofputil_decode_nxst_flow_request(fsr, &b, false);
- case OFPUTIL_NXST_AGGREGATE_REQUEST:
- return ofputil_decode_nxst_flow_request(fsr, oh, true);
+ case OFPRAW_NXST_AGGREGATE_REQUEST:
+ return ofputil_decode_nxst_flow_request(fsr, &b, true);
default:
/* Hey, the caller lied. */
enum ofputil_protocol protocol)
{
struct ofpbuf *msg;
+ enum ofpraw raw;
switch (protocol) {
case OFPUTIL_P_OF10:
case OFPUTIL_P_OF10_TID: {
struct ofp_flow_stats_request *ofsr;
- int type;
- type = fsr->aggregate ? OFPST_AGGREGATE : OFPST_FLOW;
- ofsr = ofputil_make_stats_request(sizeof *ofsr, type, 0, &msg);
+ raw = (fsr->aggregate
+ ? OFPRAW_OFPST_AGGREGATE_REQUEST
+ : OFPRAW_OFPST_FLOW_REQUEST);
+ msg = ofpraw_alloc(raw, OFP10_VERSION, 0);
+ ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr);
ofputil_cls_rule_to_ofp10_match(&fsr->match, &ofsr->match);
ofsr->table_id = fsr->table_id;
ofsr->out_port = htons(fsr->out_port);
case OFPUTIL_P_NXM_TID: {
struct nx_flow_stats_request *nfsr;
int match_len;
- int subtype;
- subtype = fsr->aggregate ? NXST_AGGREGATE : NXST_FLOW;
- ofputil_make_stats_request(sizeof *nfsr, OFPST_VENDOR, subtype, &msg);
+ raw = (fsr->aggregate
+ ? OFPRAW_NXST_AGGREGATE_REQUEST
+ : OFPRAW_NXST_FLOW_REQUEST);
+ msg = ofpraw_alloc(raw, OFP10_VERSION, 0);
+ ofpbuf_put_zeros(msg, sizeof *nfsr);
match_len = nx_put_match(msg, false, &fsr->match,
fsr->cookie, fsr->cookie_mask);
- nfsr = msg->data;
+ nfsr = msg->l3;
nfsr->out_port = htons(fsr->out_port);
nfsr->match_len = htons(match_len);
nfsr->table_id = fsr->table_id;
bool flow_age_extension,
struct ofpbuf *ofpacts)
{
- const struct ofputil_msg_type *type;
- int code;
+ enum ofperr error;
+ enum ofpraw raw;
- ofputil_decode_msg_type(msg->l2 ? msg->l2 : msg->data, &type);
- code = ofputil_msg_type_code(type);
- if (!msg->l2) {
- msg->l2 = msg->data;
- if (code == OFPUTIL_OFPST_FLOW_REPLY) {
- ofpbuf_pull(msg, sizeof(struct ofp_stats_msg));
- } else if (code == OFPUTIL_NXST_FLOW_REPLY) {
- ofpbuf_pull(msg, sizeof(struct nicira_stats_msg));
- } else {
- NOT_REACHED();
- }
+ error = (msg->l2
+ ? ofpraw_decode(&raw, msg->l2)
+ : ofpraw_pull(&raw, msg));
+ if (error) {
+ return error;
}
if (!msg->size) {
return EOF;
- } else if (code == OFPUTIL_OFPST_FLOW_REPLY) {
+ } else if (raw == OFPRAW_OFPST_FLOW_REPLY) {
const struct ofp_flow_stats *ofs;
size_t length;
fs->hard_age = -1;
fs->packet_count = ntohll(get_32aligned_be64(&ofs->packet_count));
fs->byte_count = ntohll(get_32aligned_be64(&ofs->byte_count));
- } else if (code == OFPUTIL_NXST_FLOW_REPLY) {
+ } else if (raw == OFPRAW_NXST_FLOW_REPLY) {
const struct nx_flow_stats *nfs;
size_t match_len, actions_len, length;
struct list *replies)
{
struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
- const struct ofp_stats_msg *osm = reply->data;
size_t start_ofs = reply->size;
+ enum ofpraw raw;
- if (osm->type == htons(OFPST_FLOW)) {
+ ofpraw_decode_partial(&raw, reply->data, reply->size);
+ if (raw == OFPRAW_OFPST_FLOW_REPLY) {
struct ofp_flow_stats *ofs;
ofpbuf_put_uninit(reply, sizeof *ofs);
htonll(unknown_to_zero(fs->packet_count)));
put_32aligned_be64(&ofs->byte_count,
htonll(unknown_to_zero(fs->byte_count)));
- } else if (osm->type == htons(OFPST_VENDOR)) {
+ } else if (raw == OFPRAW_NXST_FLOW_REPLY) {
struct nx_flow_stats *nfs;
int match_len;
NOT_REACHED();
}
- ofputil_postappend_stats_reply(start_ofs, replies);
+ ofpmp_postappend(replies, start_ofs);
}
/* Converts abstract ofputil_aggregate_stats 'stats' into an OFPST_AGGREGATE or
struct ofpbuf *
ofputil_encode_aggregate_stats_reply(
const struct ofputil_aggregate_stats *stats,
- const struct ofp_stats_msg *request)
+ const struct ofp_header *request)
{
struct ofpbuf *msg;
+ enum ofpraw raw;
- if (request->type == htons(OFPST_AGGREGATE)) {
+ ofpraw_decode(&raw, request);
+ if (raw == OFPRAW_OFPST_AGGREGATE_REQUEST) {
struct ofp_aggregate_stats_reply *asr;
- asr = ofputil_make_stats_reply(sizeof *asr, request, &msg);
+ msg = ofpraw_alloc_reply(OFPRAW_OFPST_AGGREGATE_REPLY, request, 0);
+ asr = ofpbuf_put_zeros(msg, sizeof *asr);
put_32aligned_be64(&asr->packet_count,
htonll(unknown_to_zero(stats->packet_count)));
put_32aligned_be64(&asr->byte_count,
htonll(unknown_to_zero(stats->byte_count)));
asr->flow_count = htonl(stats->flow_count);
- } else if (request->type == htons(OFPST_VENDOR)) {
+ } else if (raw == OFPRAW_NXST_AGGREGATE_REQUEST) {
struct nx_aggregate_stats_reply *nasr;
- nasr = ofputil_make_stats_reply(sizeof *nasr, request, &msg);
- assert(nasr->nsm.subtype == htonl(NXST_AGGREGATE));
+ msg = ofpraw_alloc_reply(OFPRAW_NXST_AGGREGATE_REPLY, request, 0);
+ nasr = ofpbuf_put_zeros(msg, sizeof *nasr);
nasr->packet_count = htonll(stats->packet_count);
nasr->byte_count = htonll(stats->byte_count);
nasr->flow_count = htonl(stats->flow_count);
return msg;
}
+enum ofperr
+ofputil_decode_aggregate_stats_reply(struct ofputil_aggregate_stats *stats,
+ const struct ofp_header *reply)
+{
+ struct ofpbuf msg;
+ enum ofpraw raw;
+
+ ofpbuf_use_const(&msg, reply, ntohs(reply->length));
+ raw = ofpraw_pull_assert(&msg);
+ if (raw == OFPRAW_OFPST_AGGREGATE_REPLY) {
+ struct ofp_aggregate_stats_reply *asr = msg.l3;
+
+ stats->packet_count = ntohll(get_32aligned_be64(&asr->packet_count));
+ stats->byte_count = ntohll(get_32aligned_be64(&asr->byte_count));
+ stats->flow_count = ntohl(asr->flow_count);
+ } else if (raw == OFPRAW_NXST_AGGREGATE_REPLY) {
+ struct nx_aggregate_stats_reply *nasr = msg.l3;
+
+ stats->packet_count = ntohll(nasr->packet_count);
+ stats->byte_count = ntohll(nasr->byte_count);
+ stats->flow_count = ntohl(nasr->flow_count);
+ } else {
+ NOT_REACHED();
+ }
+
+ return 0;
+}
+
/* Converts an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message 'oh' into an
* abstract ofputil_flow_removed in 'fr'. Returns 0 if successful, otherwise
* an OpenFlow error code. */
ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
const struct ofp_header *oh)
{
- const struct ofputil_msg_type *type;
- enum ofputil_msg_code code;
+ enum ofpraw raw;
+ struct ofpbuf b;
- ofputil_decode_msg_type(oh, &type);
- code = ofputil_msg_type_code(type);
- if (code == OFPUTIL_OFPT_FLOW_REMOVED) {
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+ if (raw == OFPRAW_OFPT10_FLOW_REMOVED) {
const struct ofp_flow_removed *ofr;
- ofr = (const struct ofp_flow_removed *) oh;
+ ofr = ofpbuf_pull(&b, sizeof *ofr);
+
ofputil_cls_rule_from_ofp10_match(&ofr->match, ntohs(ofr->priority),
&fr->rule);
fr->cookie = ofr->cookie;
fr->idle_timeout = ntohs(ofr->idle_timeout);
fr->packet_count = ntohll(ofr->packet_count);
fr->byte_count = ntohll(ofr->byte_count);
- } else if (code == OFPUTIL_NXT_FLOW_REMOVED) {
+ } else if (raw == OFPRAW_NXT_FLOW_REMOVED) {
struct nx_flow_removed *nfr;
- struct ofpbuf b;
int error;
- ofpbuf_use_const(&b, oh, ntohs(oh->length));
-
nfr = ofpbuf_pull(&b, sizeof *nfr);
error = nx_pull_match(&b, ntohs(nfr->match_len), ntohs(nfr->priority),
&fr->rule, NULL, NULL);
case OFPUTIL_P_OF10_TID: {
struct ofp_flow_removed *ofr;
- ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, htonl(0),
- &msg);
+ msg = ofpraw_alloc_xid(OFPRAW_OFPT10_FLOW_REMOVED, OFP10_VERSION,
+ htonl(0), 0);
+ ofr = ofpbuf_put_zeros(msg, sizeof *ofr);
ofputil_cls_rule_to_ofp10_match(&fr->rule, &ofr->match);
ofr->cookie = fr->cookie;
ofr->priority = htons(fr->rule.priority);
struct nx_flow_removed *nfr;
int match_len;
- make_nxmsg_xid(sizeof *nfr, NXT_FLOW_REMOVED, htonl(0), &msg);
+ msg = ofpraw_alloc_xid(OFPRAW_NXT_FLOW_REMOVED, OFP10_VERSION,
+ htonl(0), NXM_TYPICAL_LEN);
+ nfr = ofpbuf_put_zeros(msg, sizeof *nfr);
match_len = nx_put_match(msg, false, &fr->rule, 0, 0);
- nfr = msg->data;
+ nfr = msg->l3;
nfr->cookie = fr->cookie;
nfr->priority = htons(fr->rule.priority);
nfr->reason = fr->reason;
ofputil_decode_packet_in(struct ofputil_packet_in *pin,
const struct ofp_header *oh)
{
- const struct ofputil_msg_type *type;
- enum ofputil_msg_code code;
+ enum ofpraw raw;
+ struct ofpbuf b;
- ofputil_decode_msg_type(oh, &type);
- code = ofputil_msg_type_code(type);
memset(pin, 0, sizeof *pin);
- if (code == OFPUTIL_OFPT_PACKET_IN) {
- const struct ofp_packet_in *opi = (const struct ofp_packet_in *) oh;
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+ if (raw == OFPRAW_OFPT10_PACKET_IN) {
+ const struct ofp_packet_in *opi;
+
+ opi = ofpbuf_pull(&b, offsetof(struct ofp_packet_in, data));
pin->packet = opi->data;
- pin->packet_len = ntohs(opi->header.length)
- - offsetof(struct ofp_packet_in, data);
+ pin->packet_len = b.size;
pin->fmd.in_port = ntohs(opi->in_port);
pin->reason = opi->reason;
pin->buffer_id = ntohl(opi->buffer_id);
pin->total_len = ntohs(opi->total_len);
- } else if (code == OFPUTIL_NXT_PACKET_IN) {
+ } else if (raw == OFPRAW_NXT_PACKET_IN) {
const struct nx_packet_in *npi;
struct cls_rule rule;
- struct ofpbuf b;
int error;
- ofpbuf_use_const(&b, oh, ntohs(oh->length));
-
npi = ofpbuf_pull(&b, sizeof *npi);
error = nx_pull_match_loose(&b, ntohs(npi->match_len), 0, &rule, NULL,
NULL);
/* Add OFPT_PACKET_IN. */
if (packet_in_format == NXPIF_OPENFLOW10) {
- size_t header_len = offsetof(struct ofp_packet_in, data);
struct ofp_packet_in *opi;
- packet = ofpbuf_new(send_len + header_len);
- opi = ofpbuf_put_zeros(packet, header_len);
- opi->header.version = OFP10_VERSION;
- opi->header.type = OFPT_PACKET_IN;
+ packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
+ htonl(0), send_len);
+ opi = ofpbuf_put_zeros(packet, offsetof(struct ofp_packet_in, data));
opi->total_len = htons(pin->total_len);
opi->in_port = htons(pin->fmd.in_port);
opi->reason = pin->reason;
size_t match_len;
size_t i;
- /* Estimate of required PACKET_IN length includes the NPI header, space
- * for the match (2 times sizeof the metadata seems like enough), 2
- * bytes for padding, and the packet length. */
- packet = ofpbuf_new(sizeof *npi + sizeof(struct flow_metadata) * 2
- + 2 + send_len);
-
cls_rule_init_catchall(&rule, 0);
cls_rule_set_tun_id_masked(&rule, pin->fmd.tun_id,
pin->fmd.tun_id_mask);
cls_rule_set_in_port(&rule, pin->fmd.in_port);
+ /* The final argument is just an estimate of the space required. */
+ packet = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION,
+ htonl(0), (sizeof(struct flow_metadata) * 2
+ + 2 + send_len));
ofpbuf_put_zeros(packet, sizeof *npi);
match_len = nx_put_match(packet, false, &rule, 0, 0);
ofpbuf_put_zeros(packet, 2);
ofpbuf_put(packet, pin->packet, send_len);
- npi = packet->data;
- npi->nxh.header.version = OFP10_VERSION;
- npi->nxh.header.type = OFPT_VENDOR;
- npi->nxh.vendor = htonl(NX_VENDOR_ID);
- npi->nxh.subtype = htonl(NXT_PACKET_IN);
-
+ npi = packet->l3;
npi->buffer_id = htonl(pin->buffer_id);
npi->total_len = htons(pin->total_len);
npi->reason = pin->reason;
} else {
NOT_REACHED();
}
- update_openflow_length(packet);
+ ofpmsg_update_length(packet);
return packet;
}
* Returns 0 if successful, otherwise an OFPERR_* value. */
enum ofperr
ofputil_decode_packet_out(struct ofputil_packet_out *po,
- const struct ofp_packet_out *opo,
+ const struct ofp_header *oh,
struct ofpbuf *ofpacts)
{
+ const struct ofp_packet_out *opo;
enum ofperr error;
+ enum ofpraw raw;
struct ofpbuf b;
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+ assert(raw == OFPRAW_OFPT10_PACKET_OUT);
+
+ opo = ofpbuf_pull(&b, sizeof *opo);
po->buffer_id = ntohl(opo->buffer_id);
po->in_port = ntohs(opo->in_port);
if (po->in_port >= OFPP_MAX && po->in_port != OFPP_LOCAL
return OFPERR_NXBRC_BAD_IN_PORT;
}
- ofpbuf_use_const(&b, opo, ntohs(opo->header.length));
- ofpbuf_pull(&b, sizeof *opo);
-
error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts);
if (error) {
return error;
if (ofp_version == OFP10_VERSION) {
struct ofp10_phy_port *opp;
- opp = ofputil_append_stats_reply(sizeof *opp, replies);
+ opp = ofpmp_append(replies, sizeof *opp);
ofputil_encode_ofp10_phy_port(pp, opp);
} else {
struct ofp11_port *op;
- op = ofputil_append_stats_reply(sizeof *op, replies);
+ op = ofpmp_append(replies, sizeof *op);
ofputil_encode_ofp11_port(pp, op);
}
}
* ofputil_pull_phy_port(). Returns 0 if successful, otherwise an
* OFPERR_* value. */
enum ofperr
-ofputil_decode_switch_features(const struct ofp_switch_features *osf,
+ofputil_decode_switch_features(const struct ofp_header *oh,
struct ofputil_switch_features *features,
struct ofpbuf *b)
{
- ofpbuf_use_const(b, osf, ntohs(osf->header.length));
- ofpbuf_pull(b, sizeof *osf);
+ const struct ofp_switch_features *osf;
+ enum ofpraw raw;
+
+ ofpbuf_use_const(b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(b);
+ osf = ofpbuf_pull(b, sizeof *osf);
features->datapath_id = ntohll(osf->datapath_id);
features->n_buffers = ntohl(osf->n_buffers);
features->n_tables = osf->n_tables;
features->capabilities = ntohl(osf->capabilities) & OFPC_COMMON;
- if (b->size % ofputil_get_phy_port_size(osf->header.version)) {
+ if (b->size % ofputil_get_phy_port_size(oh->version)) {
return OFPERR_OFPBRC_BAD_LEN;
}
- if (osf->header.version == OFP10_VERSION) {
+ if (raw == OFPRAW_OFPT10_FEATURES_REPLY) {
if (osf->capabilities & htonl(OFPC10_STP)) {
features->capabilities |= OFPUTIL_C_STP;
}
features->actions = decode_action_bits(osf->actions, of10_action_bits);
- } else if (osf->header.version == OFP11_VERSION) {
+ } else if (raw == OFPRAW_OFPT11_FEATURES_REPLY) {
if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) {
features->capabilities |= OFPUTIL_C_GROUP_STATS;
}
return 0;
}
-/* Returns true if the maximum number of ports are in 'osf'. */
+/* Returns true if the maximum number of ports are in 'oh'. */
static bool
-max_ports_in_features(const struct ofp_switch_features *osf)
+max_ports_in_features(const struct ofp_header *oh)
{
- size_t pp_size = ofputil_get_phy_port_size(osf->header.version);
- return ntohs(osf->header.length) + pp_size > UINT16_MAX;
+ size_t pp_size = ofputil_get_phy_port_size(oh->version);
+ return ntohs(oh->length) + pp_size > UINT16_MAX;
}
/* Given a buffer 'b' that contains a Features Reply message, checks if
bool
ofputil_switch_features_ports_trunc(struct ofpbuf *b)
{
- struct ofp_switch_features *osf = b->data;
+ struct ofp_header *oh = b->data;
- if (max_ports_in_features(osf)) {
+ if (max_ports_in_features(oh)) {
/* Remove all the ports. */
- b->size = sizeof(*osf);
- update_openflow_length(b);
+ b->size = (sizeof(struct ofp_header)
+ + sizeof(struct ofp_switch_features));
+ ofpmsg_update_length(b);
return true;
}
{
struct ofp_switch_features *osf;
struct ofpbuf *b;
-
- osf = make_openflow_xid(sizeof *osf, OFPT_FEATURES_REPLY, xid, &b);
- osf->header.version = ofputil_protocol_to_ofp_version(protocol);
+ uint8_t version;
+
+ version = ofputil_protocol_to_ofp_version(protocol);
+ b = ofpraw_alloc_xid(version == OFP10_VERSION
+ ? OFPRAW_OFPT10_FEATURES_REPLY
+ : OFPRAW_OFPT11_FEATURES_REPLY,
+ version, xid, 0);
+ osf = ofpbuf_put_zeros(b, sizeof *osf);
osf->datapath_id = htonll(features->datapath_id);
osf->n_buffers = htonl(features->n_buffers);
osf->n_tables = features->n_tables;
osf->capabilities = htonl(features->capabilities & OFPC_COMMON);
- if (osf->header.version == OFP10_VERSION) {
+ if (version == OFP10_VERSION) {
if (features->capabilities & OFPUTIL_C_STP) {
osf->capabilities |= htonl(OFPC10_STP);
}
ofputil_put_switch_features_port(const struct ofputil_phy_port *pp,
struct ofpbuf *b)
{
- const struct ofp_switch_features *osf = b->data;
+ const struct ofp_header *oh = b->data;
- ofputil_put_phy_port(osf->header.version, pp, b);
+ ofputil_put_phy_port(oh->version, pp, b);
}
\f
/* ofputil_port_status */
/* Decodes the OpenFlow "port status" message in '*ops' into an abstract form
* in '*ps'. Returns 0 if successful, otherwise an OFPERR_* value. */
enum ofperr
-ofputil_decode_port_status(const struct ofp_port_status *ops,
+ofputil_decode_port_status(const struct ofp_header *oh,
struct ofputil_port_status *ps)
{
+ const struct ofp_port_status *ops;
struct ofpbuf b;
int retval;
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ ofpraw_pull_assert(&b);
+ ops = ofpbuf_pull(&b, sizeof *ops);
+
if (ops->reason != OFPPR_ADD &&
ops->reason != OFPPR_DELETE &&
ops->reason != OFPPR_MODIFY) {
}
ps->reason = ops->reason;
- ofpbuf_use_const(&b, ops, ntohs(ops->header.length));
- ofpbuf_pull(&b, sizeof *ops);
- retval = ofputil_pull_phy_port(ops->header.version, &b, &ps->desc);
+ retval = ofputil_pull_phy_port(oh->version, &b, &ps->desc);
assert(retval != EOF);
return retval;
}
{
struct ofp_port_status *ops;
struct ofpbuf *b;
-
- b = ofpbuf_new(sizeof *ops + sizeof(struct ofp11_port));
- ops = put_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, htonl(0), b);
- ops->header.version = ofputil_protocol_to_ofp_version(protocol);
+ uint8_t version;
+
+ version = ofputil_protocol_to_ofp_version(protocol);
+ b = ofpraw_alloc_xid(version == OFP10_VERSION
+ ? OFPRAW_OFPT10_PORT_STATUS
+ : OFPRAW_OFPT11_PORT_STATUS,
+ version, htonl(0), 0);
+ ops = ofpbuf_put_zeros(b, sizeof *ops);
ops->reason = ps->reason;
- ofputil_put_phy_port(ops->header.version, &ps->desc, b);
- update_openflow_length(b);
+ ofputil_put_phy_port(version, &ps->desc, b);
+ ofpmsg_update_length(b);
return b;
}
\f
ofputil_decode_port_mod(const struct ofp_header *oh,
struct ofputil_port_mod *pm)
{
- if (oh->version == OFP10_VERSION) {
- const struct ofp10_port_mod *opm = (const struct ofp10_port_mod *) oh;
+ enum ofpraw raw;
+ struct ofpbuf b;
- if (oh->length != htons(sizeof *opm)) {
- return OFPERR_OFPBRC_BAD_LEN;
- }
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+
+ if (raw == OFPRAW_OFPT10_PORT_MOD) {
+ const struct ofp10_port_mod *opm = b.data;
pm->port_no = ntohs(opm->port_no);
memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
pm->config = ntohl(opm->config) & OFPPC10_ALL;
pm->mask = ntohl(opm->mask) & OFPPC10_ALL;
pm->advertise = netdev_port_features_from_ofp10(opm->advertise);
- } else if (oh->version == OFP11_VERSION) {
- const struct ofp11_port_mod *opm = (const struct ofp11_port_mod *) oh;
+ } else if (raw == OFPRAW_OFPT11_PORT_MOD) {
+ const struct ofp11_port_mod *opm = b.data;
enum ofperr error;
- if (oh->length != htons(sizeof *opm)) {
- return OFPERR_OFPBRC_BAD_LEN;
- }
-
error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no);
if (error) {
return error;
pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
pm->advertise = netdev_port_features_from_ofp11(opm->advertise);
} else {
- return OFPERR_OFPBRC_BAD_VERSION;
+ return OFPERR_OFPBRC_BAD_TYPE;
}
pm->config &= pm->mask;
if (ofp_version == OFP10_VERSION) {
struct ofp10_port_mod *opm;
- opm = make_openflow(sizeof *opm, OFPT10_PORT_MOD, &b);
+ b = ofpraw_alloc(OFPRAW_OFPT10_PORT_MOD, ofp_version, 0);
+ opm = ofpbuf_put_zeros(b, sizeof *opm);
opm->port_no = htons(pm->port_no);
memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
opm->config = htonl(pm->config & OFPPC10_ALL);
} else if (ofp_version == OFP11_VERSION) {
struct ofp11_port_mod *opm;
- opm = make_openflow(sizeof *opm, OFPT11_PORT_MOD, &b);
+ b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0);
+ opm = ofpbuf_put_zeros(b, sizeof *opm);
opm->port_no = htonl(pm->port_no);
memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
opm->config = htonl(pm->config & OFPPC11_ALL);
if (!msg->l2) {
msg->l2 = msg->data;
- ofpbuf_pull(msg, sizeof(struct nicira_stats_msg));
+ ofpraw_pull_assert(msg);
}
if (!msg->size) {
int match_len;
if (!msg->size) {
- ofputil_put_stats_header(alloc_xid(), OFPT10_STATS_REQUEST,
- htons(OFPST_VENDOR),
- htonl(NXST_FLOW_MONITOR), msg);
+ ofpraw_put(OFPRAW_NXST_FLOW_MONITOR_REQUEST, OFP10_VERSION, msg);
}
start_ofs = msg->size;
if (!msg->l2) {
msg->l2 = msg->data;
- ofpbuf_pull(msg, sizeof(struct nicira_stats_msg));
+ ofpraw_pull_assert(msg);
}
if (!msg->size) {
uint32_t
ofputil_decode_flow_monitor_cancel(const struct ofp_header *oh)
{
- return ntohl(((const struct nx_flow_monitor_cancel *) oh)->id);
+ const struct nx_flow_monitor_cancel *cancel = ofpmsg_body(oh);
+
+ return ntohl(cancel->id);
}
struct ofpbuf *
struct nx_flow_monitor_cancel *nfmc;
struct ofpbuf *msg;
- nfmc = make_nxmsg(sizeof *nfmc, NXT_FLOW_MONITOR_CANCEL, &msg);
+ msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MONITOR_CANCEL, OFP10_VERSION, 0);
+ nfmc = ofpbuf_put_uninit(msg, sizeof *nfmc);
nfmc->id = htonl(id);
return msg;
}
{
struct ofpbuf *msg;
- msg = ofpbuf_new(1024);
- ofputil_put_stats_header(htonl(0), OFPT10_STATS_REPLY,
- htons(OFPST_VENDOR),
- htonl(NXST_FLOW_MONITOR), msg);
+ msg = ofpraw_alloc_xid(OFPRAW_NXST_FLOW_MONITOR_REPLY, OFP10_VERSION,
+ htonl(0), 1024);
list_init(replies);
list_push_back(replies, &msg->list_node);
nfuh->length = htons(msg->size - start_ofs);
nfuh->event = htons(update->event);
- ofputil_postappend_stats_reply(start_ofs, replies);
+ ofpmp_postappend(replies, start_ofs);
}
\f
struct ofpbuf *
ofputil_encode_packet_out(const struct ofputil_packet_out *po)
{
struct ofp_packet_out *opo;
+ size_t actions_ofs;
struct ofpbuf *msg;
size_t size;
- size = sizeof *opo + po->ofpacts_len;
+ size = po->ofpacts_len;
if (po->buffer_id == UINT32_MAX) {
size += po->packet_len;
}
- msg = ofpbuf_new(size);
- put_openflow(sizeof *opo, OFPT_PACKET_OUT, msg);
+ msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size);
+ ofpbuf_put_zeros(msg, sizeof *opo);
+ actions_ofs = msg->size;
ofpacts_put_openflow10(po->ofpacts, po->ofpacts_len, msg);
- opo = msg->data;
+ opo = msg->l3;
opo->buffer_id = htonl(po->buffer_id);
opo->in_port = htons(po->in_port);
- opo->actions_len = htons(msg->size - sizeof *opo);
+ opo->actions_len = htons(msg->size - actions_ofs);
if (po->buffer_id == UINT32_MAX) {
ofpbuf_put(msg, po->packet, po->packet_len);
}
- update_openflow_length(msg);
+ ofpmsg_update_length(msg);
return msg;
}
-
-/* Returns a string representing the message type of 'type'. The string is the
- * enumeration constant for the type, e.g. "OFPT_HELLO". For statistics
- * messages, the constant is followed by "request" or "reply",
- * e.g. "OFPST_AGGREGATE reply". */
-const char *
-ofputil_msg_type_name(const struct ofputil_msg_type *type)
-{
- return type->name;
-}
\f
-/* Allocates and stores in '*bufferp' a new ofpbuf with a size of
- * 'openflow_len', starting with an OpenFlow header with the given 'type' and
- * an arbitrary transaction id. Allocated bytes beyond the header, if any, are
- * zeroed.
- *
- * The caller is responsible for freeing '*bufferp' when it is no longer
- * needed.
- *
- * The OpenFlow header length is initially set to 'openflow_len'; if the
- * message is later extended, the length should be updated with
- * update_openflow_length() before sending.
- *
- * Returns the header. */
-void *
-make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **bufferp)
-{
- *bufferp = ofpbuf_new(openflow_len);
- return put_openflow_xid(openflow_len, type, alloc_xid(), *bufferp);
-}
-
-/* Similar to make_openflow() but creates a Nicira vendor extension message
- * with the specific 'subtype'. 'subtype' should be in host byte order. */
-void *
-make_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf **bufferp)
-{
- return make_nxmsg_xid(openflow_len, subtype, alloc_xid(), bufferp);
-}
-
-/* Allocates and stores in '*bufferp' a new ofpbuf with a size of
- * 'openflow_len', starting with an OpenFlow header with the given 'type' and
- * transaction id 'xid'. Allocated bytes beyond the header, if any, are
- * zeroed.
- *
- * The caller is responsible for freeing '*bufferp' when it is no longer
- * needed.
- *
- * The OpenFlow header length is initially set to 'openflow_len'; if the
- * message is later extended, the length should be updated with
- * update_openflow_length() before sending.
- *
- * Returns the header. */
-void *
-make_openflow_xid(size_t openflow_len, uint8_t type, ovs_be32 xid,
- struct ofpbuf **bufferp)
-{
- *bufferp = ofpbuf_new(openflow_len);
- return put_openflow_xid(openflow_len, type, xid, *bufferp);
-}
-
-/* Similar to make_openflow_xid() but creates a Nicira vendor extension message
- * with the specific 'subtype'. 'subtype' should be in host byte order. */
-void *
-make_nxmsg_xid(size_t openflow_len, uint32_t subtype, ovs_be32 xid,
- struct ofpbuf **bufferp)
-{
- *bufferp = ofpbuf_new(openflow_len);
- return put_nxmsg_xid(openflow_len, subtype, xid, *bufferp);
-}
-
-/* Appends 'openflow_len' bytes to 'buffer', starting with an OpenFlow header
- * with the given 'type' and an arbitrary transaction id. Allocated bytes
- * beyond the header, if any, are zeroed.
- *
- * The OpenFlow header length is initially set to 'openflow_len'; if the
- * message is later extended, the length should be updated with
- * update_openflow_length() before sending.
- *
- * Returns the header. */
-void *
-put_openflow(size_t openflow_len, uint8_t type, struct ofpbuf *buffer)
-{
- return put_openflow_xid(openflow_len, type, alloc_xid(), buffer);
-}
-
-/* Appends 'openflow_len' bytes to 'buffer', starting with an OpenFlow header
- * with the given 'type' and an transaction id 'xid'. Allocated bytes beyond
- * the header, if any, are zeroed.
- *
- * The OpenFlow header length is initially set to 'openflow_len'; if the
- * message is later extended, the length should be updated with
- * update_openflow_length() before sending.
- *
- * Returns the header. */
-void *
-put_openflow_xid(size_t openflow_len, uint8_t type, ovs_be32 xid,
- struct ofpbuf *buffer)
-{
- struct ofp_header *oh;
-
- assert(openflow_len >= sizeof *oh);
- assert(openflow_len <= UINT16_MAX);
-
- oh = ofpbuf_put_uninit(buffer, openflow_len);
- oh->version = OFP10_VERSION;
- oh->type = type;
- oh->length = htons(openflow_len);
- oh->xid = xid;
- memset(oh + 1, 0, openflow_len - sizeof *oh);
- return oh;
-}
-
-/* Similar to put_openflow() but append a Nicira vendor extension message with
- * the specific 'subtype'. 'subtype' should be in host byte order. */
-void *
-put_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf *buffer)
-{
- return put_nxmsg_xid(openflow_len, subtype, alloc_xid(), buffer);
-}
-
-/* Similar to put_openflow_xid() but append a Nicira vendor extension message
- * with the specific 'subtype'. 'subtype' should be in host byte order. */
-void *
-put_nxmsg_xid(size_t openflow_len, uint32_t subtype, ovs_be32 xid,
- struct ofpbuf *buffer)
-{
- struct nicira_header *nxh;
-
- nxh = put_openflow_xid(openflow_len, OFPT_VENDOR, xid, buffer);
- nxh->vendor = htonl(NX_VENDOR_ID);
- nxh->subtype = htonl(subtype);
- return nxh;
-}
-
-/* Updates the 'length' field of the OpenFlow message in 'buffer' to
- * 'buffer->size'. */
-void
-update_openflow_length(struct ofpbuf *buffer)
-{
- struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh);
- oh->length = htons(buffer->size);
-}
-
-void
-ofputil_put_stats_header(ovs_be32 xid, uint8_t ofp_type,
- ovs_be16 ofpst_type, ovs_be32 nxst_subtype,
- struct ofpbuf *msg)
-{
- if (ofpst_type == htons(OFPST_VENDOR)) {
- struct nicira_stats_msg *nsm;
-
- nsm = put_openflow_xid(sizeof *nsm, ofp_type, xid, msg);
- nsm->vsm.osm.type = ofpst_type;
- nsm->vsm.vendor = htonl(NX_VENDOR_ID);
- nsm->subtype = nxst_subtype;
- } else {
- struct ofp_stats_msg *osm;
-
- osm = put_openflow_xid(sizeof *osm, ofp_type, xid, msg);
- osm->type = ofpst_type;
- }
-}
-
-/* Creates a statistics request message with total length 'openflow_len'
- * (including all headers) and the given 'ofpst_type', and stores the buffer
- * containing the new message in '*bufferp'. If 'ofpst_type' is OFPST_VENDOR
- * then 'nxst_subtype' is used as the Nicira vendor extension statistics
- * subtype (otherwise 'nxst_subtype' is ignored).
- *
- * Initializes bytes following the headers to all-bits-zero.
- *
- * Returns the first byte of the new message. */
-void *
-ofputil_make_stats_request(size_t openflow_len, uint16_t ofpst_type,
- uint32_t nxst_subtype, struct ofpbuf **bufferp)
-{
- struct ofpbuf *msg;
-
- msg = *bufferp = ofpbuf_new(openflow_len);
- ofputil_put_stats_header(alloc_xid(), OFPT10_STATS_REQUEST,
- htons(ofpst_type), htonl(nxst_subtype), msg);
- ofpbuf_padto(msg, openflow_len);
-
- return msg->data;
-}
-
-static void
-put_stats_reply__(const struct ofp_stats_msg *request, struct ofpbuf *msg)
-{
- ovs_be32 nxst_subtype;
-
- assert(request->header.type == OFPT10_STATS_REQUEST ||
- request->header.type == OFPT10_STATS_REPLY);
-
- nxst_subtype = (request->type != htons(OFPST_VENDOR)
- ? htonl(0)
- : ((const struct nicira_stats_msg *) request)->subtype);
- ofputil_put_stats_header(request->header.xid, OFPT10_STATS_REPLY,
- request->type, nxst_subtype, msg);
-}
-
-/* Creates a statistics reply message with total length 'openflow_len'
- * (including all headers) and the same type (either a standard OpenFlow
- * statistics type or a Nicira extension type and subtype) as 'request', and
- * stores the buffer containing the new message in '*bufferp'.
- *
- * Initializes bytes following the headers to all-bits-zero.
- *
- * Returns the first byte of the new message. */
-void *
-ofputil_make_stats_reply(size_t openflow_len,
- const struct ofp_stats_msg *request,
- struct ofpbuf **bufferp)
-{
- struct ofpbuf *msg;
-
- msg = *bufferp = ofpbuf_new(openflow_len);
- put_stats_reply__(request, msg);
- ofpbuf_padto(msg, openflow_len);
-
- return msg->data;
-}
-
-/* Initializes 'replies' as a list of ofpbufs that will contain a series of
- * replies to 'request', which should be an OpenFlow or Nicira extension
- * statistics request. Initially 'replies' will have a single reply message
- * that has only a header. The functions ofputil_reserve_stats_reply() and
- * ofputil_append_stats_reply() may be used to add to the reply. */
-void
-ofputil_start_stats_reply(const struct ofp_stats_msg *request,
- struct list *replies)
-{
- struct ofpbuf *msg;
-
- msg = ofpbuf_new(1024);
- put_stats_reply__(request, msg);
-
- list_init(replies);
- list_push_back(replies, &msg->list_node);
-}
-
-/* Prepares to append up to 'len' bytes to the series of statistics replies in
- * 'replies', which should have been initialized with
- * ofputil_start_stats_reply(). Returns an ofpbuf with at least 'len' bytes of
- * tailroom. (The 'len' bytes have not actually be allocated; the caller must
- * do so with e.g. ofpbuf_put_uninit().) */
-struct ofpbuf *
-ofputil_reserve_stats_reply(size_t len, struct list *replies)
-{
- struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
- struct ofp_stats_msg *osm = msg->data;
-
- if (msg->size + len <= UINT16_MAX) {
- ofpbuf_prealloc_tailroom(msg, len);
- } else {
- osm->flags |= htons(OFPSF_REPLY_MORE);
-
- msg = ofpbuf_new(MAX(1024, sizeof(struct nicira_stats_msg) + len));
- put_stats_reply__(osm, msg);
- list_push_back(replies, &msg->list_node);
- }
- return msg;
-}
-
-/* Appends 'len' bytes to the series of statistics replies in 'replies', and
- * returns the first byte. */
-void *
-ofputil_append_stats_reply(size_t len, struct list *replies)
-{
- return ofpbuf_put_uninit(ofputil_reserve_stats_reply(len, replies), len);
-}
-
-/* Sometimes, when composing stats replies, it's difficult to predict how long
- * an individual reply chunk will be before actually encoding it into the reply
- * buffer. This function allows easy handling of this case: just encode the
- * reply, then use this function to break the message into two pieces if it
- * exceeds the OpenFlow message limit.
- *
- * In detail, if the final stats message in 'replies' is too long for OpenFlow,
- * this function breaks it into two separate stats replies, the first one with
- * the first 'start_ofs' bytes, the second one containing the bytes from that
- * offset onward. */
-void
-ofputil_postappend_stats_reply(size_t start_ofs, struct list *replies)
-{
- struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
-
- assert(start_ofs <= UINT16_MAX);
- if (msg->size > UINT16_MAX) {
- size_t len = msg->size - start_ofs;
- memcpy(ofputil_append_stats_reply(len, replies),
- (const uint8_t *) msg->data + start_ofs, len);
- msg->size = start_ofs;
- }
-}
-
-/* Returns the first byte past the ofp_stats_msg header in 'oh'. */
-const void *
-ofputil_stats_body(const struct ofp_header *oh)
-{
- assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
- return (const struct ofp_stats_msg *) oh + 1;
-}
-
-/* Returns the number of bytes past the ofp_stats_msg header in 'oh'. */
-size_t
-ofputil_stats_body_len(const struct ofp_header *oh)
-{
- assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
- return ntohs(oh->length) - sizeof(struct ofp_stats_msg);
-}
-
-/* Returns the first byte past the nicira_stats_msg header in 'oh'. */
-const void *
-ofputil_nxstats_body(const struct ofp_header *oh)
-{
- assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
- return ((const struct nicira_stats_msg *) oh) + 1;
-}
-
-/* Returns the number of bytes past the nicira_stats_msg header in 'oh'. */
-size_t
-ofputil_nxstats_body_len(const struct ofp_header *oh)
-{
- assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
- return ntohs(oh->length) - sizeof(struct nicira_stats_msg);
-}
-
/* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */
struct ofpbuf *
make_echo_request(void)
{
- struct ofp_header *rq;
- struct ofpbuf *out = ofpbuf_new(sizeof *rq);
- rq = ofpbuf_put_uninit(out, sizeof *rq);
- rq->version = OFP10_VERSION;
- rq->type = OFPT_ECHO_REQUEST;
- rq->length = htons(sizeof *rq);
- rq->xid = htonl(0);
- return out;
+ return ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
+ htonl(0), 0);
}
/* Creates and returns an OFPT_ECHO_REPLY message matching the
struct ofpbuf *
make_echo_reply(const struct ofp_header *rq)
{
- size_t size = ntohs(rq->length);
- struct ofpbuf *out = ofpbuf_new(size);
- struct ofp_header *reply = ofpbuf_put(out, rq, size);
- reply->type = OFPT_ECHO_REPLY;
- return out;
+ struct ofpbuf rq_buf;
+ struct ofpbuf *reply;
+
+ ofpbuf_use_const(&rq_buf, rq, ntohs(rq->length));
+ ofpraw_pull_assert(&rq_buf);
+
+ reply = ofpraw_alloc_reply(OFPRAW_OFPT_ECHO_REPLY, rq, rq_buf.size);
+ ofpbuf_put(reply, rq_buf.data, rq_buf.size);
+ return reply;
}
struct ofpbuf *
ofputil_encode_barrier_request(void)
{
- struct ofpbuf *msg;
-
- make_openflow(sizeof(struct ofp_header), OFPT10_BARRIER_REQUEST, &msg);
- return msg;
+ return ofpraw_alloc(OFPRAW_OFPT10_BARRIER_REQUEST, OFP10_VERSION, 0);
}
const char *
struct cls_rule;
struct ofpbuf;
-/* Basic decoding and length validation of OpenFlow messages. */
-enum ofputil_msg_code {
- OFPUTIL_MSG_INVALID,
-
- /* OFPT_* messages. */
- OFPUTIL_OFPT_HELLO,
- OFPUTIL_OFPT_ERROR,
- OFPUTIL_OFPT_ECHO_REQUEST,
- OFPUTIL_OFPT_ECHO_REPLY,
- OFPUTIL_OFPT_FEATURES_REQUEST,
- OFPUTIL_OFPT_FEATURES_REPLY,
- OFPUTIL_OFPT_GET_CONFIG_REQUEST,
- OFPUTIL_OFPT_GET_CONFIG_REPLY,
- OFPUTIL_OFPT_SET_CONFIG,
- OFPUTIL_OFPT_PACKET_IN,
- OFPUTIL_OFPT_FLOW_REMOVED,
- OFPUTIL_OFPT_PORT_STATUS,
- OFPUTIL_OFPT_PACKET_OUT,
- OFPUTIL_OFPT_FLOW_MOD,
- OFPUTIL_OFPT_PORT_MOD,
- OFPUTIL_OFPT_BARRIER_REQUEST,
- OFPUTIL_OFPT_BARRIER_REPLY,
- OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST,
- OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY,
-
- /* OFPST_* stat requests. */
- OFPUTIL_OFPST_DESC_REQUEST,
- OFPUTIL_OFPST_FLOW_REQUEST,
- OFPUTIL_OFPST_AGGREGATE_REQUEST,
- OFPUTIL_OFPST_TABLE_REQUEST,
- OFPUTIL_OFPST_PORT_REQUEST,
- OFPUTIL_OFPST_QUEUE_REQUEST,
- OFPUTIL_OFPST_PORT_DESC_REQUEST,
-
- /* OFPST_* stat replies. */
- OFPUTIL_OFPST_DESC_REPLY,
- OFPUTIL_OFPST_FLOW_REPLY,
- OFPUTIL_OFPST_QUEUE_REPLY,
- OFPUTIL_OFPST_PORT_REPLY,
- OFPUTIL_OFPST_TABLE_REPLY,
- OFPUTIL_OFPST_AGGREGATE_REPLY,
- OFPUTIL_OFPST_PORT_DESC_REPLY,
-
- /* NXT_* messages. */
- OFPUTIL_NXT_ROLE_REQUEST,
- OFPUTIL_NXT_ROLE_REPLY,
- OFPUTIL_NXT_SET_FLOW_FORMAT,
- OFPUTIL_NXT_FLOW_MOD_TABLE_ID,
- OFPUTIL_NXT_FLOW_MOD,
- OFPUTIL_NXT_FLOW_REMOVED,
- OFPUTIL_NXT_SET_PACKET_IN_FORMAT,
- OFPUTIL_NXT_PACKET_IN,
- OFPUTIL_NXT_FLOW_AGE,
- OFPUTIL_NXT_SET_ASYNC_CONFIG,
- OFPUTIL_NXT_SET_CONTROLLER_ID,
- OFPUTIL_NXT_FLOW_MONITOR_CANCEL,
- OFPUTIL_NXT_FLOW_MONITOR_PAUSED,
- OFPUTIL_NXT_FLOW_MONITOR_RESUMED,
-
- /* NXST_* stat requests. */
- OFPUTIL_NXST_FLOW_REQUEST,
- OFPUTIL_NXST_AGGREGATE_REQUEST,
- OFPUTIL_NXST_FLOW_MONITOR_REQUEST,
-
- /* NXST_* stat replies. */
- OFPUTIL_NXST_FLOW_REPLY,
- OFPUTIL_NXST_AGGREGATE_REPLY,
- OFPUTIL_NXST_FLOW_MONITOR_REPLY,
-};
-
-struct ofputil_msg_type;
-enum ofperr ofputil_decode_msg_type(const struct ofp_header *,
- const struct ofputil_msg_type **);
-enum ofperr ofputil_decode_msg_type_partial(const struct ofp_header *,
- size_t length,
- const struct ofputil_msg_type **);
-enum ofputil_msg_code ofputil_msg_type_code(const struct ofputil_msg_type *);
-const char *ofputil_msg_type_name(const struct ofputil_msg_type *);
-
/* Port numbers. */
enum ofperr ofputil_port_from_ofp11(ovs_be32 ofp11_port, uint16_t *ofp10_port);
ovs_be32 ofputil_port_to_ofp11(uint16_t ofp10_port);
struct ofpbuf *ofputil_encode_aggregate_stats_reply(
const struct ofputil_aggregate_stats *stats,
- const struct ofp_stats_msg *request);
+ const struct ofp_header *request);
+enum ofperr ofputil_decode_aggregate_stats_reply(
+ struct ofputil_aggregate_stats *,
+ const struct ofp_header *reply);
/* Flow removed message, independent of protocol. */
struct ofputil_flow_removed {
};
enum ofperr ofputil_decode_packet_out(struct ofputil_packet_out *,
- const struct ofp_packet_out *,
+ const struct ofp_header *,
struct ofpbuf *ofpacts);
struct ofpbuf *ofputil_encode_packet_out(const struct ofputil_packet_out *);
enum ofputil_action_bitmap actions;
};
-enum ofperr ofputil_decode_switch_features(const struct ofp_switch_features *,
+enum ofperr ofputil_decode_switch_features(const struct ofp_header *,
struct ofputil_switch_features *,
struct ofpbuf *);
struct ofputil_phy_port desc;
};
-enum ofperr ofputil_decode_port_status(const struct ofp_port_status *,
+enum ofperr ofputil_decode_port_status(const struct ofp_header *,
struct ofputil_port_status *);
struct ofpbuf *ofputil_encode_port_status(const struct ofputil_port_status *,
enum ofputil_protocol);
uint32_t ofputil_decode_flow_monitor_cancel(const struct ofp_header *);
struct ofpbuf *ofputil_encode_flow_monitor_cancel(uint32_t id);
-/* OpenFlow protocol utility functions. */
-void *make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **);
-void *make_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf **);
-
-void *make_openflow_xid(size_t openflow_len, uint8_t type,
- ovs_be32 xid, struct ofpbuf **);
-void *make_nxmsg_xid(size_t openflow_len, uint32_t subtype, ovs_be32 xid,
- struct ofpbuf **);
-
-void *put_openflow(size_t openflow_len, uint8_t type, struct ofpbuf *);
-void *put_openflow_xid(size_t openflow_len, uint8_t type, ovs_be32 xid,
- struct ofpbuf *);
-
-void *put_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf *);
-void *put_nxmsg_xid(size_t openflow_len, uint32_t subtype, ovs_be32 xid,
- struct ofpbuf *);
-
-void update_openflow_length(struct ofpbuf *);
-
-void *ofputil_make_stats_request(size_t openflow_len, uint16_t type,
- uint32_t subtype, struct ofpbuf **);
-void *ofputil_make_stats_reply(size_t openflow_len,
- const struct ofp_stats_msg *request,
- struct ofpbuf **);
-
-void ofputil_put_stats_header(ovs_be32 xid, uint8_t ofp_type,
- ovs_be16 ofpst_type, ovs_be32 nxst_subtype,
- struct ofpbuf *);
-
-void ofputil_start_stats_reply(const struct ofp_stats_msg *request,
- struct list *);
-struct ofpbuf *ofputil_reserve_stats_reply(size_t len, struct list *);
-void *ofputil_append_stats_reply(size_t len, struct list *);
-void ofputil_postappend_stats_reply(size_t start_ofs, struct list *);
-
+/* Encoding OpenFlow stats messages. */
void ofputil_append_port_desc_stats_reply(uint8_t ofp_version,
const struct ofputil_phy_port *pp,
struct list *replies);
-const void *ofputil_stats_body(const struct ofp_header *);
-size_t ofputil_stats_body_len(const struct ofp_header *);
-
-const void *ofputil_nxstats_body(const struct ofp_header *);
-size_t ofputil_nxstats_body_len(const struct ofp_header *);
-
-/* */
+/* Encoding simple OpenFlow messages. */
struct ofpbuf *make_echo_request(void);
struct ofpbuf *make_echo_reply(const struct ofp_header *rq);
#include <stdlib.h>
#include <string.h>
#include "coverage.h"
+#include "ofp-msgs.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
static bool
is_admitted_msg(const struct ofpbuf *b)
{
- struct ofp_header *oh = b->data;
- uint8_t type = oh->type;
- return !(type < 32
- && (1u << type) & ((1u << OFPT_HELLO) |
- (1u << OFPT_ERROR) |
- (1u << OFPT_ECHO_REQUEST) |
- (1u << OFPT_ECHO_REPLY) |
- (1u << OFPT_VENDOR) |
- (1u << OFPT_FEATURES_REQUEST) |
- (1u << OFPT_FEATURES_REPLY) |
- (1u << OFPT_GET_CONFIG_REQUEST) |
- (1u << OFPT_GET_CONFIG_REPLY) |
- (1u << OFPT_SET_CONFIG)));
+ enum ofptype type;
+ enum ofperr error;
+
+ error = ofptype_decode(&type, b->data);
+ if (error) {
+ return false;
+ }
+
+ switch (type) {
+ case OFPTYPE_HELLO:
+ case OFPTYPE_ERROR:
+ case OFPTYPE_ECHO_REQUEST:
+ case OFPTYPE_ECHO_REPLY:
+ case OFPTYPE_FEATURES_REQUEST:
+ case OFPTYPE_FEATURES_REPLY:
+ case OFPTYPE_GET_CONFIG_REQUEST:
+ case OFPTYPE_GET_CONFIG_REPLY:
+ case OFPTYPE_SET_CONFIG:
+ return false;
+
+ case OFPTYPE_PACKET_IN:
+ case OFPTYPE_FLOW_REMOVED:
+ case OFPTYPE_PORT_STATUS:
+ case OFPTYPE_PACKET_OUT:
+ case OFPTYPE_FLOW_MOD:
+ case OFPTYPE_PORT_MOD:
+ case OFPTYPE_BARRIER_REQUEST:
+ case OFPTYPE_BARRIER_REPLY:
+ case OFPTYPE_DESC_STATS_REQUEST:
+ case OFPTYPE_DESC_STATS_REPLY:
+ case OFPTYPE_FLOW_STATS_REQUEST:
+ case OFPTYPE_FLOW_STATS_REPLY:
+ case OFPTYPE_AGGREGATE_STATS_REQUEST:
+ case OFPTYPE_AGGREGATE_STATS_REPLY:
+ case OFPTYPE_TABLE_STATS_REQUEST:
+ case OFPTYPE_TABLE_STATS_REPLY:
+ case OFPTYPE_PORT_STATS_REQUEST:
+ case OFPTYPE_PORT_STATS_REPLY:
+ case OFPTYPE_QUEUE_STATS_REQUEST:
+ case OFPTYPE_QUEUE_STATS_REPLY:
+ case OFPTYPE_PORT_DESC_STATS_REQUEST:
+ case OFPTYPE_PORT_DESC_STATS_REPLY:
+ case OFPTYPE_ROLE_REQUEST:
+ case OFPTYPE_ROLE_REPLY:
+ case OFPTYPE_SET_FLOW_FORMAT:
+ case OFPTYPE_FLOW_MOD_TABLE_ID:
+ case OFPTYPE_SET_PACKET_IN_FORMAT:
+ case OFPTYPE_FLOW_AGE:
+ case OFPTYPE_SET_ASYNC_CONFIG:
+ case OFPTYPE_SET_CONTROLLER_ID:
+ case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
+ case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
+ case OFPTYPE_FLOW_MONITOR_CANCEL:
+ case OFPTYPE_FLOW_MONITOR_PAUSED:
+ case OFPTYPE_FLOW_MONITOR_RESUMED:
+ default:
+ return true;
+ }
}
/* Returns true if 'rc' is currently logging information about connection
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
return STREAM_SSL;
case PAIR('{', '"'):
return STREAM_JSONRPC;
- case PAIR(OFP10_VERSION, OFPT_HELLO):
+ case PAIR(OFP10_VERSION, 0 /* OFPT_HELLO */):
return STREAM_OPENFLOW;
}
}
#include "fatal-signal.h"
#include "flow.h"
#include "ofp-errors.h"
+#include "ofp-msgs.h"
#include "ofp-print.h"
#include "ofp-util.h"
#include "ofpbuf.h"
struct ofpbuf *b;
int retval;
- make_openflow(sizeof(struct ofp_header), OFPT_HELLO, &b);
+ b = ofpraw_alloc(OFPRAW_OFPT_HELLO, OFP10_VERSION, 0);
retval = do_send(vconn, b);
if (!retval) {
vconn->state = VCS_RECV_HELLO;
retval = do_recv(vconn, &b);
if (!retval) {
- struct ofp_header *oh = b->data;
+ const struct ofp_header *oh = b->data;
+ enum ofptype type;
+ enum ofperr error;
- if (oh->type == OFPT_HELLO) {
+ error = ofptype_decode(&type, b->data);
+ if (!error && type == OFPTYPE_HELLO) {
if (b->size > sizeof *oh) {
struct ds msg = DS_EMPTY_INITIALIZER;
ds_put_format(&msg, "%s: extra-long hello:\n", vconn->name);
int
vconn_recv(struct vconn *vconn, struct ofpbuf **msgp)
{
- int retval = vconn_connect(vconn);
+ struct ofpbuf *msg;
+ int retval;
+
+ retval = vconn_connect(vconn);
+ if (!retval) {
+ retval = do_recv(vconn, &msg);
+ }
if (!retval) {
- retval = do_recv(vconn, msgp);
+ const struct ofp_header *oh = msg->data;
+ if (oh->version != vconn->version) {
+ enum ofptype type;
+
+ if (ofptype_decode(&type, msg->data)
+ || (type != OFPTYPE_HELLO &&
+ type != OFPTYPE_ERROR &&
+ type != OFPTYPE_ECHO_REQUEST &&
+ type != OFPTYPE_ECHO_REPLY)) {
+ VLOG_ERR_RL(&bad_ofmsg_rl, "%s: received OpenFlow version "
+ "0x%02"PRIx8" != expected %02x",
+ vconn->name, oh->version, vconn->version);
+ ofpbuf_delete(msg);
+ retval = EPROTO;
+ }
+ }
}
+
+ *msgp = retval ? NULL : msg;
return retval;
}
{
int retval = (vconn->class->recv)(vconn, msgp);
if (!retval) {
- struct ofp_header *oh;
-
COVERAGE_INC(vconn_received);
if (VLOG_IS_DBG_ENABLED()) {
char *s = ofp_to_string((*msgp)->data, (*msgp)->size, 1);
VLOG_DBG_RL(&ofmsg_rl, "%s: received: %s", vconn->name, s);
free(s);
}
-
- oh = ofpbuf_at_assert(*msgp, 0, sizeof *oh);
- if ((oh->version != vconn->version || oh->version == 0)
- && oh->type != OFPT_HELLO
- && oh->type != OFPT_ERROR
- && oh->type != OFPT_ECHO_REQUEST
- && oh->type != OFPT_ECHO_REPLY
- && oh->type != OFPT_VENDOR)
- {
- if (vconn->version == 0) {
- VLOG_ERR_RL(&bad_ofmsg_rl,
- "%s: received OpenFlow message type %"PRIu8" "
- "before version negotiation complete",
- vconn->name, oh->type);
- } else {
- VLOG_ERR_RL(&bad_ofmsg_rl,
- "%s: received OpenFlow version 0x%02"PRIx8" "
- "!= expected %02x",
- vconn->name, oh->version, vconn->version);
- }
- ofpbuf_delete(*msgp);
- retval = EPROTO;
- }
- }
- if (retval) {
- *msgp = NULL;
}
return retval;
}
int retval;
assert(msg->size >= sizeof(struct ofp_header));
- assert(((struct ofp_header *) msg->data)->length == htons(msg->size));
+
+ ofpmsg_update_length(msg);
if (!VLOG_IS_DBG_ENABLED()) {
COVERAGE_INC(vconn_sent);
retval = (vconn->class->send)(vconn, msg);
#include "in-band.h"
#include "odp-util.h"
#include "ofp-actions.h"
+#include "ofp-msgs.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "ofproto-provider.h"
static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(10, 10);
if (!VLOG_DROP_INFO(&err_rl)) {
- const struct ofputil_msg_type *type;
const char *type_name;
size_t request_len;
+ enum ofpraw raw;
request_len = ntohs(request->length);
- type_name = (!ofputil_decode_msg_type_partial(request,
- MIN(64, request_len),
- &type)
- ? ofputil_msg_type_name(type)
+ type_name = (!ofpraw_decode_partial(&raw, request,
+ MIN(64, request_len))
+ ? ofpraw_get_name(raw)
: "invalid");
VLOG_INFO("%s: sending %s error reply to %s message",
ofconn_send(const struct ofconn *ofconn, struct ofpbuf *msg,
struct rconn_packet_counter *counter)
{
- update_openflow_length(msg);
+ ofpmsg_update_length(msg);
rconn_send(ofconn->rconn, msg, counter);
}
\f
COVERAGE_INC(ofmonitor_pause);
ofconn->monitor_paused = monitor_seqno++;
- make_nxmsg_xid(sizeof(struct nicira_header),
- NXT_FLOW_MONITOR_PAUSED, htonl(0), &pause);
+ pause = ofpraw_alloc_xid(OFPRAW_NXT_FLOW_MONITOR_PAUSED,
+ OFP10_VERSION, htonl(0), 0);
ofconn_send(ofconn, pause, ofconn->monitor_counter);
}
}
static void
ofmonitor_resume(struct ofconn *ofconn)
{
- struct ofpbuf *resume;
+ struct ofpbuf *resumed;
struct ofmonitor *m;
struct list rules;
struct list msgs;
list_init(&msgs);
ofmonitor_compose_refresh_updates(&rules, &msgs);
- make_nxmsg_xid(sizeof(struct nicira_header),
- NXT_FLOW_MONITOR_RESUMED, htonl(0), &resume);
- list_push_back(&msgs, &resume->list_node);
+ resumed = ofpraw_alloc_xid(OFPRAW_NXT_FLOW_MONITOR_RESUMED, OFP10_VERSION,
+ htonl(0), 0);
+ list_push_back(&msgs, &resumed->list_node);
ofconn_send_replies(ofconn, &msgs);
ofconn->monitor_paused = 0;
#include "nx-match.h"
#include "ofp-actions.h"
#include "ofp-errors.h"
+#include "ofp-msgs.h"
#include "ofp-print.h"
#include "ofp-util.h"
#include "ofpbuf.h"
struct ofpbuf *buf;
/* Send reply. */
- osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
+ buf = ofpraw_alloc_reply(OFPRAW_OFPT_GET_CONFIG_REPLY, oh, 0);
+ osc = ofpbuf_put_uninit(buf, sizeof *osc);
flags = ofproto->frag_handling;
if (ofconn_get_invalid_ttl_to_controller(ofconn)) {
flags |= OFPC_INVALID_TTL_TO_CONTROLLER;
}
static enum ofperr
-handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc)
+handle_set_config(struct ofconn *ofconn, const struct ofp_header *oh)
{
+ const struct ofp_switch_config *osc = ofpmsg_body(oh);
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
uint16_t flags = ntohs(osc->flags);
}
static enum ofperr
-handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo)
+handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofproto *p = ofconn_get_ofproto(ofconn);
struct ofputil_packet_out po;
/* Decode message. */
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
- error = ofputil_decode_packet_out(&po, opo, &ofpacts);
+ error = ofputil_decode_packet_out(&po, oh, &ofpacts);
if (error) {
goto exit_free_ofpacts;
}
static enum ofperr
handle_desc_stats_request(struct ofconn *ofconn,
- const struct ofp_stats_msg *request)
+ const struct ofp_header *request)
{
struct ofproto *p = ofconn_get_ofproto(ofconn);
struct ofp_desc_stats *ods;
struct ofpbuf *msg;
- ods = ofputil_make_stats_reply(sizeof *ods, request, &msg);
+ msg = ofpraw_alloc_stats_reply(request, 0);
+ ods = ofpbuf_put_zeros(msg, sizeof *ods);
ovs_strlcpy(ods->mfr_desc, p->mfr_desc, sizeof ods->mfr_desc);
ovs_strlcpy(ods->hw_desc, p->hw_desc, sizeof ods->hw_desc);
ovs_strlcpy(ods->sw_desc, p->sw_desc, sizeof ods->sw_desc);
static enum ofperr
handle_table_stats_request(struct ofconn *ofconn,
- const struct ofp_stats_msg *request)
+ const struct ofp_header *request)
{
struct ofproto *p = ofconn_get_ofproto(ofconn);
struct ofp_table_stats *ots;
struct ofpbuf *msg;
size_t i;
- ofputil_make_stats_reply(sizeof(struct ofp_stats_msg), request, &msg);
-
+ msg = ofpraw_alloc_stats_reply(request, sizeof *ots * p->n_tables);
ots = ofpbuf_put_zeros(msg, sizeof *ots * p->n_tables);
for (i = 0; i < p->n_tables; i++) {
ots[i].table_id = i;
* netdev_get_stats() will log errors. */
ofproto_port_get_stats(port, &stats);
- ops = ofputil_append_stats_reply(sizeof *ops, replies);
+ ops = ofpmp_append(replies, sizeof *ops);
ops->port_no = htons(port->pp.port_no);
memset(ops->pad, 0, sizeof ops->pad);
put_32aligned_be64(&ops->rx_packets, htonll(stats.rx_packets));
static enum ofperr
handle_port_stats_request(struct ofconn *ofconn,
- const struct ofp_port_stats_request *psr)
+ const struct ofp_header *request)
{
struct ofproto *p = ofconn_get_ofproto(ofconn);
+ const struct ofp_port_stats_request *psr = ofpmsg_body(request);
struct ofport *port;
struct list replies;
- ofputil_start_stats_reply(&psr->osm, &replies);
+ ofpmp_init(&replies, request);
if (psr->port_no != htons(OFPP_NONE)) {
port = ofproto_get_port(p, ntohs(psr->port_no));
if (port) {
static enum ofperr
handle_port_desc_stats_request(struct ofconn *ofconn,
- const struct ofp_stats_msg *osm)
+ const struct ofp_header *request)
{
struct ofproto *p = ofconn_get_ofproto(ofconn);
struct ofport *port;
struct list replies;
- ofputil_start_stats_reply(osm, &replies);
+ ofpmp_init(&replies, request);
HMAP_FOR_EACH (port, hmap_node, &p->ports) {
ofputil_append_port_desc_stats_reply(ofconn_get_protocol(ofconn),
static enum ofperr
handle_flow_stats_request(struct ofconn *ofconn,
- const struct ofp_stats_msg *osm)
+ const struct ofp_header *request)
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
struct ofputil_flow_stats_request fsr;
struct rule *rule;
enum ofperr error;
- error = ofputil_decode_flow_stats_request(&fsr, &osm->header);
+ error = ofputil_decode_flow_stats_request(&fsr, request);
if (error) {
return error;
}
return error;
}
- ofputil_start_stats_reply(osm, &replies);
+ ofpmp_init(&replies, request);
LIST_FOR_EACH (rule, ofproto_node, &rules) {
long long int now = time_msec();
struct ofputil_flow_stats fs;
static enum ofperr
handle_aggregate_stats_request(struct ofconn *ofconn,
- const struct ofp_stats_msg *osm)
+ const struct ofp_header *oh)
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
struct ofputil_flow_stats_request request;
struct rule *rule;
enum ofperr error;
- error = ofputil_decode_flow_stats_request(&request, &osm->header);
+ error = ofputil_decode_flow_stats_request(&request, oh);
if (error) {
return error;
}
stats.byte_count = UINT64_MAX;
}
- reply = ofputil_encode_aggregate_stats_reply(&stats, osm);
+ reply = ofputil_encode_aggregate_stats_reply(&stats, oh);
ofconn_send_reply(ofconn, reply);
return 0;
{
struct ofp_queue_stats *reply;
- reply = ofputil_append_stats_reply(sizeof *reply, &cbdata->replies);
+ reply = ofpmp_append(&cbdata->replies, sizeof *reply);
reply->port_no = htons(cbdata->ofport->pp.port_no);
memset(reply->pad, 0, sizeof reply->pad);
reply->queue_id = htonl(queue_id);
static enum ofperr
handle_queue_stats_request(struct ofconn *ofconn,
- const struct ofp_queue_stats_request *qsr)
+ const struct ofp_header *rq)
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+ const struct ofp_queue_stats_request *qsr = ofpmsg_body(rq);
struct queue_stats_cbdata cbdata;
unsigned int port_no;
struct ofport *port;
COVERAGE_INC(ofproto_queue_req);
- ofputil_start_stats_reply(&qsr->osm, &cbdata.replies);
+ ofpmp_init(&cbdata.replies, rq);
port_no = ntohs(qsr->port_no);
queue_id = ntohl(qsr->queue_id);
static enum ofperr
handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
- struct nx_role_request *nrr = (struct nx_role_request *) oh;
+ const struct nx_role_request *nrr = ofpmsg_body(oh);
struct nx_role_request *reply;
struct ofpbuf *buf;
uint32_t role;
ofconn_set_role(ofconn, role);
- reply = make_nxmsg_xid(sizeof *reply, NXT_ROLE_REPLY, oh->xid, &buf);
+ buf = ofpraw_alloc_reply(OFPRAW_NXT_ROLE_REPLY, oh, 0);
+ reply = ofpbuf_put_zeros(buf, sizeof *reply);
reply->role = htonl(role);
ofconn_send_reply(ofconn, buf);
handle_nxt_flow_mod_table_id(struct ofconn *ofconn,
const struct ofp_header *oh)
{
- const struct nx_flow_mod_table_id *msg
- = (const struct nx_flow_mod_table_id *) oh;
+ const struct nx_flow_mod_table_id *msg = ofpmsg_body(oh);
enum ofputil_protocol cur, next;
cur = ofconn_get_protocol(ofconn);
static enum ofperr
handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
{
- const struct nx_set_flow_format *msg
- = (const struct nx_set_flow_format *) oh;
+ const struct nx_set_flow_format *msg = ofpmsg_body(oh);
enum ofputil_protocol cur, next;
enum ofputil_protocol next_base;
handle_nxt_set_packet_in_format(struct ofconn *ofconn,
const struct ofp_header *oh)
{
- const struct nx_set_packet_in_format *msg;
+ const struct nx_set_packet_in_format *msg = ofpmsg_body(oh);
uint32_t format;
- msg = (const struct nx_set_packet_in_format *) oh;
format = ntohl(msg->format);
if (format != NXPIF_OPENFLOW10 && format != NXPIF_NXM) {
return OFPERR_OFPBRC_EPERM;
static enum ofperr
handle_nxt_set_async_config(struct ofconn *ofconn, const struct ofp_header *oh)
{
- const struct nx_async_config *msg = (const struct nx_async_config *) oh;
+ const struct nx_async_config *msg = ofpmsg_body(oh);
uint32_t master[OAM_N_TYPES];
uint32_t slave[OAM_N_TYPES];
handle_nxt_set_controller_id(struct ofconn *ofconn,
const struct ofp_header *oh)
{
- const struct nx_controller_id *nci;
+ const struct nx_controller_id *nci = ofpmsg_body(oh);
- nci = (const struct nx_controller_id *) oh;
if (!is_all_zeros(nci->zero, sizeof nci->zero)) {
return OFPERR_NXBRC_MUST_BE_ZERO;
}
return OFPROTO_POSTPONE;
}
- make_openflow_xid(sizeof *oh, OFPT10_BARRIER_REPLY, oh->xid, &buf);
+ buf = ofpraw_alloc_reply((oh->version == OFP10_VERSION
+ ? OFPRAW_OFPT10_BARRIER_REPLY
+ : OFPRAW_OFPT11_BARRIER_REPLY), oh, 0);
ofconn_send_reply(ofconn, buf);
return 0;
}
}
static enum ofperr
-handle_flow_monitor_request(struct ofconn *ofconn,
- const struct ofp_stats_msg *osm)
+handle_flow_monitor_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
struct ofmonitor **monitors;
size_t i;
error = 0;
- ofpbuf_use_const(&b, osm, ntohs(osm->header.length));
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
monitors = NULL;
n_monitors = allocated_monitors = 0;
for (;;) {
ofproto_collect_ofmonitor_initial_rules(monitors[i], &rules);
}
- ofputil_start_stats_reply(osm, &replies);
+ ofpmp_init(&replies, oh);
ofmonitor_compose_refresh_updates(&rules, &replies);
ofconn_send_replies(ofconn, &replies);
handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
{
const struct ofp_header *oh = msg->data;
- const struct ofputil_msg_type *type;
+ enum ofptype type;
enum ofperr error;
- error = ofputil_decode_msg_type(oh, &type);
+ error = ofptype_decode(&type, oh);
if (error) {
return error;
}
- switch (ofputil_msg_type_code(type)) {
+ switch (type) {
/* OpenFlow requests. */
- case OFPUTIL_OFPT_ECHO_REQUEST:
+ case OFPTYPE_ECHO_REQUEST:
return handle_echo_request(ofconn, oh);
- case OFPUTIL_OFPT_FEATURES_REQUEST:
+ case OFPTYPE_FEATURES_REQUEST:
return handle_features_request(ofconn, oh);
- case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
+ case OFPTYPE_GET_CONFIG_REQUEST:
return handle_get_config_request(ofconn, oh);
- case OFPUTIL_OFPT_SET_CONFIG:
- return handle_set_config(ofconn, msg->data);
+ case OFPTYPE_SET_CONFIG:
+ return handle_set_config(ofconn, oh);
- case OFPUTIL_OFPT_PACKET_OUT:
- return handle_packet_out(ofconn, msg->data);
+ case OFPTYPE_PACKET_OUT:
+ return handle_packet_out(ofconn, oh);
- case OFPUTIL_OFPT_PORT_MOD:
+ case OFPTYPE_PORT_MOD:
return handle_port_mod(ofconn, oh);
- case OFPUTIL_OFPT_FLOW_MOD:
+ case OFPTYPE_FLOW_MOD:
return handle_flow_mod(ofconn, oh);
- case OFPUTIL_OFPT_BARRIER_REQUEST:
+ case OFPTYPE_BARRIER_REQUEST:
return handle_barrier_request(ofconn, oh);
/* OpenFlow replies. */
- case OFPUTIL_OFPT_ECHO_REPLY:
+ case OFPTYPE_ECHO_REPLY:
return 0;
/* Nicira extension requests. */
- case OFPUTIL_NXT_ROLE_REQUEST:
+ case OFPTYPE_ROLE_REQUEST:
return handle_role_request(ofconn, oh);
- case OFPUTIL_NXT_FLOW_MOD_TABLE_ID:
+ case OFPTYPE_FLOW_MOD_TABLE_ID:
return handle_nxt_flow_mod_table_id(ofconn, oh);
- case OFPUTIL_NXT_SET_FLOW_FORMAT:
+ case OFPTYPE_SET_FLOW_FORMAT:
return handle_nxt_set_flow_format(ofconn, oh);
- case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
+ case OFPTYPE_SET_PACKET_IN_FORMAT:
return handle_nxt_set_packet_in_format(ofconn, oh);
- case OFPUTIL_NXT_SET_CONTROLLER_ID:
+ case OFPTYPE_SET_CONTROLLER_ID:
return handle_nxt_set_controller_id(ofconn, oh);
- case OFPUTIL_NXT_FLOW_MOD:
- return handle_flow_mod(ofconn, oh);
-
- case OFPUTIL_NXT_FLOW_AGE:
+ case OFPTYPE_FLOW_AGE:
/* Nothing to do. */
return 0;
- case OFPUTIL_NXT_FLOW_MONITOR_CANCEL:
+ case OFPTYPE_FLOW_MONITOR_CANCEL:
return handle_flow_monitor_cancel(ofconn, oh);
- case OFPUTIL_NXT_SET_ASYNC_CONFIG:
+ case OFPTYPE_SET_ASYNC_CONFIG:
return handle_nxt_set_async_config(ofconn, oh);
/* Statistics requests. */
- case OFPUTIL_OFPST_DESC_REQUEST:
- return handle_desc_stats_request(ofconn, msg->data);
-
- case OFPUTIL_OFPST_FLOW_REQUEST:
- case OFPUTIL_NXST_FLOW_REQUEST:
- return handle_flow_stats_request(ofconn, msg->data);
-
- case OFPUTIL_OFPST_AGGREGATE_REQUEST:
- case OFPUTIL_NXST_AGGREGATE_REQUEST:
- return handle_aggregate_stats_request(ofconn, msg->data);
-
- case OFPUTIL_OFPST_TABLE_REQUEST:
- return handle_table_stats_request(ofconn, msg->data);
-
- case OFPUTIL_OFPST_PORT_REQUEST:
- return handle_port_stats_request(ofconn, msg->data);
-
- case OFPUTIL_OFPST_QUEUE_REQUEST:
- return handle_queue_stats_request(ofconn, msg->data);
-
- case OFPUTIL_OFPST_PORT_DESC_REQUEST:
- return handle_port_desc_stats_request(ofconn, msg->data);
-
- case OFPUTIL_NXST_FLOW_MONITOR_REQUEST:
- return handle_flow_monitor_request(ofconn, msg->data);
-
- case OFPUTIL_MSG_INVALID:
- case OFPUTIL_OFPT_HELLO:
- case OFPUTIL_OFPT_ERROR:
- case OFPUTIL_OFPT_FEATURES_REPLY:
- case OFPUTIL_OFPT_GET_CONFIG_REPLY:
- case OFPUTIL_OFPT_PACKET_IN:
- case OFPUTIL_OFPT_FLOW_REMOVED:
- case OFPUTIL_OFPT_PORT_STATUS:
- case OFPUTIL_OFPT_BARRIER_REPLY:
- case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
- case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
- case OFPUTIL_OFPST_DESC_REPLY:
- case OFPUTIL_OFPST_FLOW_REPLY:
- case OFPUTIL_OFPST_QUEUE_REPLY:
- case OFPUTIL_OFPST_PORT_REPLY:
- case OFPUTIL_OFPST_TABLE_REPLY:
- case OFPUTIL_OFPST_AGGREGATE_REPLY:
- case OFPUTIL_OFPST_PORT_DESC_REPLY:
- case OFPUTIL_NXT_ROLE_REPLY:
- case OFPUTIL_NXT_FLOW_REMOVED:
- case OFPUTIL_NXT_PACKET_IN:
- case OFPUTIL_NXT_FLOW_MONITOR_PAUSED:
- case OFPUTIL_NXT_FLOW_MONITOR_RESUMED:
- case OFPUTIL_NXST_FLOW_REPLY:
- case OFPUTIL_NXST_AGGREGATE_REPLY:
- case OFPUTIL_NXST_FLOW_MONITOR_REPLY:
+ case OFPTYPE_DESC_STATS_REQUEST:
+ return handle_desc_stats_request(ofconn, oh);
+
+ case OFPTYPE_FLOW_STATS_REQUEST:
+ return handle_flow_stats_request(ofconn, oh);
+
+ case OFPTYPE_AGGREGATE_STATS_REQUEST:
+ return handle_aggregate_stats_request(ofconn, oh);
+
+ case OFPTYPE_TABLE_STATS_REQUEST:
+ return handle_table_stats_request(ofconn, oh);
+
+ case OFPTYPE_PORT_STATS_REQUEST:
+ return handle_port_stats_request(ofconn, oh);
+
+ case OFPTYPE_QUEUE_STATS_REQUEST:
+ return handle_queue_stats_request(ofconn, oh);
+
+ case OFPTYPE_PORT_DESC_STATS_REQUEST:
+ return handle_port_desc_stats_request(ofconn, oh);
+
+ case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
+ return handle_flow_monitor_request(ofconn, oh);
+
+ case OFPTYPE_HELLO:
+ case OFPTYPE_ERROR:
+ case OFPTYPE_FEATURES_REPLY:
+ case OFPTYPE_GET_CONFIG_REPLY:
+ case OFPTYPE_PACKET_IN:
+ case OFPTYPE_FLOW_REMOVED:
+ case OFPTYPE_PORT_STATUS:
+ case OFPTYPE_BARRIER_REPLY:
+ case OFPTYPE_DESC_STATS_REPLY:
+ case OFPTYPE_FLOW_STATS_REPLY:
+ case OFPTYPE_QUEUE_STATS_REPLY:
+ case OFPTYPE_PORT_STATS_REPLY:
+ case OFPTYPE_TABLE_STATS_REPLY:
+ case OFPTYPE_AGGREGATE_STATS_REPLY:
+ case OFPTYPE_PORT_DESC_STATS_REPLY:
+ case OFPTYPE_ROLE_REPLY:
+ case OFPTYPE_FLOW_MONITOR_PAUSED:
+ case OFPTYPE_FLOW_MONITOR_RESUMED:
+ case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
default:
- return (oh->type == OFPT10_STATS_REQUEST ||
- oh->type == OFPT10_STATS_REPLY
- ? OFPERR_OFPBRC_BAD_STAT
- : OFPERR_OFPBRC_BAD_TYPE);
+ return OFPERR_OFPBRC_BAD_TYPE;
}
}
[0], [dnl
***decode error: OFPBRC_BAD_TYPE***
00000000 00 bb 00 08 ee ff 00 11- |........ |
-], [ofp_util|WARN|received OpenFlow message of unknown type 187
+], [ofp_msgs|WARN|unknown OpenFlow message (version 0, type 187)
])
AT_CLEANUP
[Datapath actions: set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=127,frag=no)),2,set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=126,frag=no)),3,4
])
+AT_CAPTURE_FILE([ofctl_monitor.log])
AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl --detach --pidfile 2> ofctl_monitor.log])
AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([ovs-vsctl --no-wait init])
dnl Start ovs-vswitchd.
- AT_CHECK([ovs-vswitchd --detach --pidfile --enable-dummy --disable-system --log-file], [0], [], [stderr])
+ AT_CHECK([ovs-vswitchd --detach --pidfile --enable-dummy --disable-system --log-file -vvconn], [0], [], [stderr])
AT_CAPTURE_FILE([ovs-vswitchd.log])
AT_CHECK([[sed < stderr '
/vlog|INFO|opened log file/d
/*
- * Copyright (c) 2009, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <stdlib.h>
#include <unistd.h>
#include "command-line.h"
+#include "ofp-msgs.h"
+#include "ofp-util.h"
+#include "ofpbuf.h"
#include "openflow/openflow.h"
#include "poll-loop.h"
#include "socket-util.h"
retval = stream_recv(stream, &hello, sizeof hello);
if (retval == sizeof hello) {
+ enum ofpraw raw;
+
CHECK(hello.version, OFP10_VERSION);
- CHECK(hello.type, OFPT_HELLO);
+ CHECK(ofpraw_decode_partial(&raw, &hello, sizeof hello), 0);
+ CHECK(raw, OFPRAW_OFPT_HELLO);
CHECK(ntohs(hello.length), sizeof hello);
break;
} else {
struct ofp_header hello;
int retval = stream_recv(stream, &hello, sizeof hello);
if (retval == sizeof hello) {
+ enum ofpraw raw;
+
CHECK(hello.version, OFP10_VERSION);
- CHECK(hello.type, OFPT_HELLO);
+ CHECK(ofpraw_decode_partial(&raw, &hello, sizeof hello), 0);
+ CHECK(raw, OFPRAW_OFPT_HELLO);
CHECK(ntohs(hello.length), sizeof hello);
read_hello = true;
} else {
test_send_plain_hello(int argc OVS_UNUSED, char *argv[])
{
const char *type = argv[1];
- struct ofp_header hello;
+ struct ofpbuf *hello;
- hello.version = OFP10_VERSION;
- hello.type = OFPT_HELLO;
- hello.length = htons(sizeof hello);
- hello.xid = htonl(0x12345678);
- test_send_hello(type, &hello, sizeof hello, 0);
+ hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP10_VERSION,
+ htonl(0x12345678), 0);
+ test_send_hello(type, hello->data, hello->size, 0);
+ ofpbuf_delete(hello);
}
/* Try connecting and sending an extra-long hello, which should succeed (since
test_send_long_hello(int argc OVS_UNUSED, char *argv[])
{
const char *type = argv[1];
- struct ofp_header hello;
- char buffer[sizeof hello * 2];
-
- hello.version = OFP10_VERSION;
- hello.type = OFPT_HELLO;
- hello.length = htons(sizeof buffer);
- hello.xid = htonl(0x12345678);
- memset(buffer, 0, sizeof buffer);
- memcpy(buffer, &hello, sizeof hello);
- test_send_hello(type, buffer, sizeof buffer, 0);
+ struct ofpbuf *hello;
+ enum { EXTRA_BYTES = 8 };
+
+ hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP10_VERSION,
+ htonl(0x12345678), EXTRA_BYTES);
+ ofpbuf_put_zeros(hello, EXTRA_BYTES);
+ ofpmsg_update_length(hello);
+ test_send_hello(type, hello->data, hello->size, 0);
+ ofpbuf_delete(hello);
}
/* Try connecting and sending an echo request instead of a hello, which should
test_send_echo_hello(int argc OVS_UNUSED, char *argv[])
{
const char *type = argv[1];
- struct ofp_header echo;
+ struct ofpbuf *echo;
- echo.version = OFP10_VERSION;
- echo.type = OFPT_ECHO_REQUEST;
- echo.length = htons(sizeof echo);
- echo.xid = htonl(0x89abcdef);
- test_send_hello(type, &echo, sizeof echo, EPROTO);
+ echo = ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
+ htonl(0x12345678), 0);
+ test_send_hello(type, echo->data, echo->size, EPROTO);
+ ofpbuf_delete(echo);
}
/* Try connecting and sending a hello packet that has its length field as 0,
test_send_invalid_version_hello(int argc OVS_UNUSED, char *argv[])
{
const char *type = argv[1];
- struct ofp_header hello;
+ struct ofpbuf *hello;
- hello.version = OFP10_VERSION - 1;
- hello.type = OFPT_HELLO;
- hello.length = htons(sizeof hello);
- hello.xid = htonl(0x12345678);
- test_send_hello(type, &hello, sizeof hello, EPROTO);
+ hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP10_VERSION,
+ htonl(0x12345678), 0);
+ ((struct ofp_header *) hello->data)->version = 0;
+ test_send_hello(type, hello->data, hello->size, EPROTO);
+ ofpbuf_delete(hello);
}
static const struct command commands[] = {
#include "odp-util.h"
#include "ofp-actions.h"
#include "ofp-errors.h"
+#include "ofp-msgs.h"
#include "ofp-parse.h"
#include "ofp-print.h"
#include "ofp-util.h"
return open_vconn__(name, "mgmt", vconnp);
}
-static void *
-alloc_stats_request(size_t rq_len, uint16_t type, struct ofpbuf **bufferp)
-{
- struct ofp_stats_msg *rq;
-
- rq = make_openflow(rq_len, OFPT10_STATS_REQUEST, bufferp);
- rq->type = htons(type);
- rq->flags = htons(0);
- return rq;
-}
-
static void
send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer)
{
- update_openflow_length(buffer);
+ ofpmsg_update_length(buffer);
run(vconn_send_block(vconn, buffer), "failed to send packet to switch");
}
struct vconn *vconn;
struct ofpbuf *reply;
- update_openflow_length(request);
+ ofpmsg_update_length(request);
open_vconn(vconn_name, &vconn);
run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
ofp_print(stdout, reply->data, reply->size, verbosity + 1);
}
static void
-dump_trivial_transaction(const char *vconn_name, uint8_t request_type)
+dump_trivial_transaction(const char *vconn_name, enum ofpraw raw)
{
struct ofpbuf *request;
- make_openflow(sizeof(struct ofp_header), request_type, &request);
+ request = ofpraw_alloc(raw, OFP10_VERSION, 0);
dump_transaction(vconn_name, request);
}
static void
dump_stats_transaction__(struct vconn *vconn, struct ofpbuf *request)
{
- ovs_be32 send_xid = ((struct ofp_header *) request->data)->xid;
- ovs_be16 stats_type = ((struct ofp_stats_msg *) request->data)->type;
+ const struct ofp_header *request_oh = request->data;
+ ovs_be32 send_xid = request_oh->xid;
+ enum ofpraw request_raw;
+ enum ofpraw reply_raw;
bool done = false;
+ ofpraw_decode_partial(&request_raw, request->data, request->size);
+ reply_raw = ofpraw_stats_request_to_reply(request_raw,
+ request_oh->version);
+
send_openflow_buffer(vconn, request);
while (!done) {
ovs_be32 recv_xid;
run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
recv_xid = ((struct ofp_header *) reply->data)->xid;
if (send_xid == recv_xid) {
- const struct ofp_stats_msg *osm = reply->data;
- const struct ofp_header *oh = reply->data;
+ enum ofpraw raw;
ofp_print(stdout, reply->data, reply->size, verbosity + 1);
- if (oh->type == OFPT_ERROR) {
+ ofpraw_decode(&raw, reply->data);
+ if (ofptype_from_ofpraw(raw) == OFPTYPE_ERROR) {
done = true;
- } else if (oh->type == OFPT10_STATS_REPLY
- && osm->type == stats_type) {
- done = !(ntohs(osm->flags) & OFPSF_REPLY_MORE);
+ } else if (raw == reply_raw) {
+ done = !ofpmp_more(reply->data);
} else {
ovs_fatal(0, "received bad reply: %s",
ofp_to_string(reply->data, reply->size,
}
static void
-dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
+dump_trivial_stats_transaction(const char *vconn_name, enum ofpraw raw)
{
struct ofpbuf *request;
- alloc_stats_request(sizeof(struct ofp_stats_msg), stats_type, &request);
+
+ request = ofpraw_alloc(raw, OFP10_VERSION, 0);
dump_stats_transaction(vconn_name, request);
}
struct ofpbuf *request, *reply;
LIST_FOR_EACH (request, list_node, requests) {
- update_openflow_length(request);
+ ofpmsg_update_length(request);
}
run(vconn_transact_multiple_noreply(vconn, requests, &reply),
fetch_switch_config(struct vconn *vconn, struct ofp_switch_config *config_)
{
struct ofp_switch_config *config;
- struct ofp_header *header;
struct ofpbuf *request;
struct ofpbuf *reply;
+ enum ofptype type;
- make_openflow(sizeof(struct ofp_header), OFPT_GET_CONFIG_REQUEST,
- &request);
+ request = ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST, OFP10_VERSION, 0);
run(vconn_transact(vconn, request, &reply),
"talking to %s", vconn_get_name(vconn));
- header = reply->data;
- if (header->type != OFPT_GET_CONFIG_REPLY ||
- header->length != htons(sizeof *config)) {
+ if (ofptype_pull(&type, reply) || type != OFPTYPE_GET_CONFIG_REPLY) {
ovs_fatal(0, "%s: bad reply to config request", vconn_get_name(vconn));
}
- config = reply->data;
+ config = ofpbuf_pull(reply, sizeof *config);
*config_ = *config;
ofpbuf_delete(reply);
}
static void
-set_switch_config(struct vconn *vconn, struct ofp_switch_config *config_)
+set_switch_config(struct vconn *vconn, const struct ofp_switch_config *config)
{
- struct ofp_switch_config *config;
- struct ofp_header save_header;
struct ofpbuf *request;
- config = make_openflow(sizeof *config, OFPT_SET_CONFIG, &request);
- save_header = config->header;
- *config = *config_;
- config->header = save_header;
+ request = ofpraw_alloc(OFPRAW_OFPT_SET_CONFIG, OFP10_VERSION, 0);
+ ofpbuf_put(request, config, sizeof *config);
transact_noreply(vconn, request);
}
struct ofpbuf *reply;
bool trunc;
- make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST,
- &request);
+ request = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, OFP10_VERSION, 0);
open_vconn(vconn_name, &vconn);
run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
/* The Features Reply may not contain all the ports, so send a
* Port Description stats request, which doesn't have size
* constraints. */
- dump_trivial_stats_transaction(vconn_name, OFPST_PORT_DESC);
+ dump_trivial_stats_transaction(vconn_name,
+ OFPRAW_OFPST_PORT_DESC_REQUEST);
}
- dump_trivial_transaction(vconn_name, OFPT_GET_CONFIG_REQUEST);
+ dump_trivial_transaction(vconn_name, OFPRAW_OFPT_GET_CONFIG_REQUEST);
}
static void
ofctl_dump_desc(int argc OVS_UNUSED, char *argv[])
{
- dump_trivial_stats_transaction(argv[1], OFPST_DESC);
+ dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_DESC_REQUEST);
}
static void
ofctl_dump_tables(int argc OVS_UNUSED, char *argv[])
{
- dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
+ dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_TABLE_REQUEST);
}
static bool
struct ofputil_phy_port *pp, bool *trunc)
{
struct ofputil_switch_features features;
- const struct ofp_switch_features *osf;
+ const struct ofp_header *oh;
struct ofpbuf *request, *reply;
struct vconn *vconn;
enum ofperr error;
+ enum ofptype type;
struct ofpbuf b;
bool found = false;
/* Fetch the switch's ofp_switch_features. */
- make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
+ request = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, OFP10_VERSION, 0);
open_vconn(vconn_name, &vconn);
run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
vconn_close(vconn);
- osf = reply->data;
- if (reply->size < sizeof *osf) {
- ovs_fatal(0, "%s: received too-short features reply (only %zu bytes)",
- vconn_name, reply->size);
+ oh = reply->data;
+ if (ofptype_decode(&type, reply->data)
+ || type != OFPTYPE_FEATURES_REPLY) {
+ ovs_fatal(0, "%s: received bad features reply", vconn_name);
}
*trunc = false;
goto exit;
}
- error = ofputil_decode_switch_features(osf, &features, &b);
+ error = ofputil_decode_switch_features(oh, &features, &b);
if (error) {
ovs_fatal(0, "%s: failed to decode features reply (%s)",
vconn_name, ofperr_to_string(error));
}
- while (!ofputil_pull_phy_port(osf->header.version, &b, pp)) {
+ while (!ofputil_pull_phy_port(oh->version, &b, pp)) {
if (port_no != UINT_MAX
? port_no == pp->port_no
: !strcmp(pp->name, port_name)) {
struct ofpbuf *request;
struct vconn *vconn;
ovs_be32 send_xid;
- struct ofpbuf b;
bool done = false;
bool found = false;
- alloc_stats_request(sizeof(struct ofp_stats_msg), OFPST_PORT_DESC,
- &request);
+ request = ofpraw_alloc(OFPRAW_OFPST_PORT_DESC_REQUEST, OFP10_VERSION, 0);
send_xid = ((struct ofp_header *) request->data)->xid;
open_vconn(vconn_name, &vconn);
run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
recv_xid = ((struct ofp_header *) reply->data)->xid;
if (send_xid == recv_xid) {
- const struct ofputil_msg_type *type;
- struct ofp_stats_msg *osm;
-
- ofputil_decode_msg_type(reply->data, &type);
- if (ofputil_msg_type_code(type) != OFPUTIL_OFPST_PORT_DESC_REPLY) {
+ struct ofp_header *oh = reply->data;
+ enum ofptype type;
+ struct ofpbuf b;
+ uint16_t flags;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ if (ofptype_pull(&type, &b)
+ || type != OFPTYPE_PORT_DESC_STATS_REPLY) {
ovs_fatal(0, "received bad reply: %s",
ofp_to_string(reply->data, reply->size,
verbosity + 1));
}
- osm = ofpbuf_at_assert(reply, 0, sizeof *osm);
- done = !(ntohs(osm->flags) & OFPSF_REPLY_MORE);
+ flags = ofpmp_flags(oh);
+ done = !(flags & OFPSF_REPLY_MORE);
if (found) {
/* We've already found the port, but we need to drain
continue;
}
- ofpbuf_use_const(&b, &osm->header, ntohs(osm->header.length));
- ofpbuf_pull(&b, sizeof(struct ofp_stats_msg));
-
- while (!ofputil_pull_phy_port(osm->header.version, &b, pp)) {
+ while (!ofputil_pull_phy_port(oh->version, &b, pp)) {
if (port_no != UINT_MAX ? port_no == pp->port_no
: !strcmp(pp->name, port_name)) {
found = true;
struct ofp_queue_stats_request *req;
struct ofpbuf *request;
- req = alloc_stats_request(sizeof *req, OFPST_QUEUE, &request);
+ request = ofpraw_alloc(OFPRAW_OFPST_QUEUE_REQUEST, OFP10_VERSION, 0);
+ req = ofpbuf_put_zeros(request, sizeof *req);
if (argc > 2 && argv[2][0] && strcasecmp(argv[2], "all")) {
req->port_no = htons(str_to_port_no(argv[1], argv[2]));
int retval;
unixctl_server_run(server);
+
while (!blocked) {
- uint8_t msg_type;
+ enum ofptype type;
retval = vconn_recv(vconn, &b);
if (retval == EAGAIN) {
fputs(s, stderr);
}
- msg_type = ((const struct ofp_header *) b->data)->type;
+ ofptype_decode(&type, b->data);
ofp_print(stderr, b->data, b->size, verbosity + 2);
ofpbuf_delete(b);
- if (barrier_aux.conn && msg_type == OFPT10_BARRIER_REPLY) {
+ if (barrier_aux.conn && type == OFPTYPE_BARRIER_REPLY) {
unixctl_command_reply(barrier_aux.conn, NULL);
barrier_aux.conn = NULL;
}
struct ofpbuf *request;
uint16_t port;
- req = alloc_stats_request(sizeof *req, OFPST_PORT, &request);
+ request = ofpraw_alloc(OFPRAW_OFPST_PORT_REQUEST, OFP10_VERSION, 0);
+ req = ofpbuf_put_zeros(request, sizeof *req);
port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_NONE;
req->port_no = htons(port);
dump_stats_transaction(argv[1], request);
static void
ofctl_dump_ports_desc(int argc OVS_UNUSED, char *argv[])
{
- dump_trivial_stats_transaction(argv[1], OFPST_PORT_DESC);
+ dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_PORT_DESC_REQUEST);
}
static void
struct vconn *vconn;
struct ofpbuf *reply;
- make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request);
+ request = make_echo_request();
open_vconn(argv[1], &vconn);
run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
if (reply->size != sizeof(struct ofp_header)) {
for (i = 0; i < 10; i++) {
struct timeval start, end;
struct ofpbuf *request, *reply;
- struct ofp_header *rq_hdr, *rpy_hdr;
+ const struct ofp_header *rpy_hdr;
+ enum ofptype type;
- rq_hdr = make_openflow(sizeof(struct ofp_header) + payload,
- OFPT_ECHO_REQUEST, &request);
- random_bytes(rq_hdr + 1, payload);
+ request = ofpraw_alloc(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
+ payload);
+ random_bytes(ofpbuf_put_uninit(request, payload), payload);
xgettimeofday(&start);
run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact");
xgettimeofday(&end);
rpy_hdr = reply->data;
- if (reply->size != request->size
- || memcmp(rpy_hdr + 1, rq_hdr + 1, payload)
- || rpy_hdr->xid != rq_hdr->xid
- || rpy_hdr->type != OFPT_ECHO_REPLY) {
+ if (ofptype_pull(&type, reply)
+ || type != OFPTYPE_ECHO_REPLY
+ || reply->size != payload
+ || memcmp(request->l3, reply->l3, payload)) {
printf("Reply does not match request. Request:\n");
ofp_print(stdout, request, request->size, verbosity + 2);
printf("Reply:\n");
ofp_print(stdout, reply, reply->size, verbosity + 2);
}
printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
- reply->size - sizeof *rpy_hdr, argv[1], ntohl(rpy_hdr->xid),
+ reply->size, argv[1], ntohl(rpy_hdr->xid),
(1000*(double)(end.tv_sec - start.tv_sec))
+ (.001*(end.tv_usec - start.tv_usec)));
ofpbuf_delete(request);
xgettimeofday(&start);
for (i = 0; i < count; i++) {
struct ofpbuf *request, *reply;
- struct ofp_header *rq_hdr;
- rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request);
- memset(rq_hdr + 1, 0, payload_size);
+ request = ofpraw_alloc(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
+ payload_size);
+ ofpbuf_put_zeros(request, payload_size);
run(vconn_transact(vconn, request, &reply), "transact");
ofpbuf_delete(reply);
}
/* Get a flow stats reply message, if we don't already have one. */
if (!reply) {
- const struct ofputil_msg_type *type;
- enum ofputil_msg_code code;
+ enum ofptype type;
+ enum ofperr error;
do {
run(vconn_recv_block(vconn, &reply),
"OpenFlow packet receive failed");
} while (((struct ofp_header *) reply->data)->xid != send_xid);
- ofputil_decode_msg_type(reply->data, &type);
- code = ofputil_msg_type_code(type);
- if (code != OFPUTIL_OFPST_FLOW_REPLY &&
- code != OFPUTIL_NXST_FLOW_REPLY) {
+ error = ofptype_decode(&type, reply->data);
+ if (error || type != OFPTYPE_FLOW_STATS_REPLY) {
ovs_fatal(0, "received bad reply: %s",
ofp_to_string(reply->data, reply->size,
verbosity + 1));