diff options
-rwxr-xr-x | build-aux/extract-ofp-msgs | 351 | ||||
-rw-r--r-- | include/openflow/nicira-ext.h | 117 | ||||
-rw-r--r-- | include/openflow/openflow-1.0.h | 74 | ||||
-rw-r--r-- | include/openflow/openflow-1.1.h | 83 | ||||
-rw-r--r-- | include/openflow/openflow-1.2.h | 23 | ||||
-rw-r--r-- | include/openflow/openflow-common.h | 75 | ||||
-rw-r--r-- | lib/.gitignore | 1 | ||||
-rw-r--r-- | lib/automake.mk | 9 | ||||
-rw-r--r-- | lib/learning-switch.c | 128 | ||||
-rw-r--r-- | lib/ofp-errors.c | 41 | ||||
-rw-r--r-- | lib/ofp-errors.h | 4 | ||||
-rw-r--r-- | lib/ofp-msgs.c | 962 | ||||
-rw-r--r-- | lib/ofp-msgs.h | 433 | ||||
-rw-r--r-- | lib/ofp-print.c | 334 | ||||
-rw-r--r-- | lib/ofp-util.c | 1372 | ||||
-rw-r--r-- | lib/ofp-util.h | 134 | ||||
-rw-r--r-- | lib/rconn.c | 72 | ||||
-rw-r--r-- | lib/stream.c | 4 | ||||
-rw-r--r-- | lib/vconn.c | 68 | ||||
-rw-r--r-- | ofproto/connmgr.c | 24 | ||||
-rw-r--r-- | ofproto/ofproto.c | 228 | ||||
-rw-r--r-- | tests/ofp-print.at | 2 | ||||
-rw-r--r-- | tests/ofproto-dpif.at | 1 | ||||
-rw-r--r-- | tests/ofproto-macros.at | 2 | ||||
-rw-r--r-- | tests/test-vconn.c | 68 | ||||
-rw-r--r-- | utilities/ovs-ofctl.c | 176 |
26 files changed, 2675 insertions, 2111 deletions
diff --git a/build-aux/extract-ofp-msgs b/build-aux/extract-ofp-msgs new file mode 100755 index 000000000..fe92dae0d --- /dev/null +++ b/build-aux/extract-ofp-msgs @@ -0,0 +1,351 @@ +#! /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 + diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 630511b0a..1c5d3448f 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -73,74 +73,26 @@ struct nx_vendor_error { 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 { @@ -200,13 +152,10 @@ 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. */ @@ -215,10 +164,9 @@ enum nx_packet_in_format { /* 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). * @@ -245,7 +193,6 @@ OFP_ASSERT(sizeof(struct nx_set_packet_in_format) == 20); * 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_*). */ @@ -267,7 +214,7 @@ struct nx_packet_in { /* 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: * @@ -289,10 +236,9 @@ OFP_ASSERT(sizeof(struct nx_packet_in) == 40); * 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. */ @@ -318,12 +264,11 @@ enum nx_role { * 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); /* Nicira vendor flow actions. */ @@ -1785,10 +1730,9 @@ enum nx_flow_format { /* 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). * @@ -1797,7 +1741,6 @@ OFP_ASSERT(sizeof(struct nx_set_flow_format) == 20); * 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). */ @@ -1820,11 +1763,10 @@ struct nx_flow_mod { * 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_*. */ @@ -1841,7 +1783,7 @@ struct nx_flow_removed { * - 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). @@ -1850,7 +1792,6 @@ OFP_ASSERT(sizeof(struct nx_flow_removed) == 56); * 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. */ @@ -1865,7 +1806,7 @@ struct nx_flow_stats_request { * 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). @@ -1918,7 +1859,6 @@ OFP_ASSERT(sizeof(struct nx_flow_stats) == 48); /* 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. */ @@ -1933,18 +1873,17 @@ struct nx_aggregate_stats_request { * 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); /* NXT_SET_CONTROLLER_ID. * @@ -1956,11 +1895,10 @@ OFP_ASSERT(sizeof(struct nx_aggregate_stats_reply) == 48); * 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. * @@ -2214,11 +2152,12 @@ struct nx_flow_update_abbrev { }; 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 */ diff --git a/include/openflow/openflow-1.0.h b/include/openflow/openflow-1.0.h index d71b007e8..23cfb8d09 100644 --- a/include/openflow/openflow-1.0.h +++ b/include/openflow/openflow-1.0.h @@ -43,31 +43,6 @@ enum ofp_port { 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 { @@ -85,12 +60,11 @@ 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). */ @@ -159,7 +133,6 @@ OFP_ASSERT(sizeof(struct ofp10_phy_port) == 48); /* 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 @@ -174,30 +147,27 @@ struct ofp10_port_mod { 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. */ @@ -210,7 +180,7 @@ struct ofp_packet_in { 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. */ @@ -289,7 +259,6 @@ OFP_ASSERT(sizeof(union ofp_action) == 8); /* 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. */ @@ -300,7 +269,7 @@ struct ofp_packet_out { * 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. */ @@ -403,7 +372,6 @@ enum ofp_flow_mod_flags { /* 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. */ @@ -423,11 +391,10 @@ struct ofp_flow_mod { 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. */ @@ -443,18 +410,16 @@ struct ofp_flow_removed { 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 { @@ -471,10 +436,9 @@ enum ofp_stats_reply_flags { #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. */ @@ -482,11 +446,10 @@ struct ofp_desc_stats { 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. */ @@ -495,7 +458,7 @@ struct ofp_flow_stats_request { 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 { @@ -520,13 +483,12 @@ OFP_ASSERT(sizeof(struct ofp_flow_stats) == 88); /* 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 { @@ -545,13 +507,12 @@ OFP_ASSERT(sizeof(struct ofp_table_stats) == 64); /* 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. */ @@ -582,12 +543,11 @@ OFP_ASSERT(sizeof(struct ofp_port_stats) == 104); /* 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. */ @@ -602,7 +562,7 @@ struct ofp_queue_stats { 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. @@ -610,7 +570,7 @@ struct ofp_vendor_stats_msg { * 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 { diff --git a/include/openflow/openflow-1.1.h b/include/openflow/openflow-1.1.h index f0f379387..7c78c6394 100644 --- a/include/openflow/openflow-1.1.h +++ b/include/openflow/openflow-1.1.h @@ -70,27 +70,6 @@ #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) @@ -143,7 +122,6 @@ struct ofp11_port { /* 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 @@ -159,11 +137,10 @@ struct ofp11_port_mod { 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. */ @@ -171,17 +148,16 @@ struct ofp11_group_mod { /* 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 { @@ -448,12 +424,11 @@ OFP_ASSERT(sizeof(struct ofp11_action_pop_mpls) == 8); /* 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 @@ -469,7 +444,6 @@ enum ofp11_table_config { /* 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 @@ -496,7 +470,7 @@ struct ofp11_flow_mod { /* 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. */ @@ -543,12 +517,11 @@ OFP_ASSERT(sizeof(struct ofp11_bucket) == 16); /* 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; @@ -559,9 +532,19 @@ struct ofp11_stats_msg { }; 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. */ @@ -579,7 +562,7 @@ struct ofp11_flow_stats_request { 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 { @@ -607,7 +590,6 @@ OFP_ASSERT(sizeof(struct ofp11_flow_stats) == 48); /* 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. */ @@ -627,23 +609,21 @@ struct ofp11_table_stats { 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. */ @@ -663,31 +643,28 @@ struct ofp11_port_stats { 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 { @@ -706,11 +683,10 @@ OFP_ASSERT(sizeof(struct ofp11_group_stats) == 32); /* 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 { @@ -724,7 +700,6 @@ OFP_ASSERT(sizeof(struct ofp11_group_desc_stats) == 8); /* 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. */ @@ -734,11 +709,10 @@ struct ofp11_packet_out { 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. */ @@ -752,11 +726,10 @@ struct ofp11_packet_in { 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. */ @@ -772,6 +745,6 @@ struct ofp11_flow_removed { 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 */ diff --git a/include/openflow/openflow-1.2.h b/include/openflow/openflow-1.2.h index 58093a84b..0a73ed17b 100644 --- a/include/openflow/openflow-1.2.h +++ b/include/openflow/openflow-1.2.h @@ -55,14 +55,6 @@ #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. @@ -264,7 +256,6 @@ enum ofp12_queue_properties { /* 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. */ @@ -290,17 +281,16 @@ struct ofp12_table_stats { 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 { @@ -321,12 +311,11 @@ OFP_ASSERT(sizeof(struct ofp12_experimenter_stats_header) == 8); /* 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 { @@ -338,7 +327,6 @@ 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_*) */ @@ -354,11 +342,10 @@ struct ofp12_packet_in { /* 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. */ @@ -374,6 +361,6 @@ struct ofp12_flow_removed { 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 */ diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h index fe91b1076..ae91c4425 100644 --- a/include/openflow/openflow-common.h +++ b/include/openflow/openflow-common.h @@ -83,32 +83,6 @@ #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. */ @@ -183,7 +157,6 @@ OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16); /* 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. */ @@ -200,7 +173,7 @@ struct ofp_switch_features { /* 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). */ @@ -293,55 +266,11 @@ enum ofp_port_reason { /* 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 diff --git a/lib/.gitignore b/lib/.gitignore index ba73f285d..f4c59add9 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -4,6 +4,7 @@ /dirs.c /coverage-counters.c /ofp-errors.inc +/ofp-msgs.inc /vswitch-idl.c /vswitch-idl.h /vswitch-idl.ovsidl diff --git a/lib/automake.mk b/lib/automake.mk index 5223423f5..ed7db7ce1 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -100,6 +100,8 @@ lib_libopenvswitch_a_SOURCES = \ 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 \ @@ -324,6 +326,13 @@ $(srcdir)/lib/ofp-errors.inc: \ $(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) diff --git a/lib/learning-switch.c b/lib/learning-switch.c index b41bea0d2..887a365ed 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -31,6 +31,7 @@ #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" @@ -81,7 +82,7 @@ static void queue_tx(struct lswitch *, struct rconn *, struct ofpbuf *); 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 *, @@ -228,84 +229,78 @@ void 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); @@ -325,11 +320,12 @@ send_features_request(struct lswitch *sw, struct rconn *rconn) 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); @@ -354,14 +350,14 @@ queue_tx(struct lswitch *sw, struct rconn *rconn, struct ofpbuf *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)); @@ -370,7 +366,7 @@ process_switch_features(struct lswitch *sw, struct ofp_switch_features *osf) 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; diff --git a/lib/ofp-errors.c b/lib/ofp-errors.c index e1349b094..13b5c4cbc 100644 --- a/lib/ofp-errors.c +++ b/lib/ofp-errors.c @@ -3,6 +3,7 @@ #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" @@ -176,25 +177,28 @@ ofperr_encode_msg__(enum ofperr error, const struct ofperr_domain *domain, 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; @@ -268,34 +272,33 @@ ofperr_get_code(enum ofperr error, const struct ofperr_domain *domain) /* 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; @@ -325,8 +328,8 @@ ofperr_decode_msg(const struct ofp_header *oh, size_t *payload_ofs) 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; } diff --git a/lib/ofp-errors.h b/lib/ofp-errors.h index dddf8d046..1af70da90 100644 --- a/lib/ofp-errors.h +++ b/lib/ofp-errors.h @@ -23,6 +23,7 @@ struct ds; struct ofp_header; +struct ofpbuf; /* Error codes. * @@ -508,7 +509,8 @@ enum ofperr ofperr_decode(const struct ofperr_domain *, 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 *); diff --git a/lib/ofp-msgs.c b/lib/ofp-msgs.c new file mode 100644 index 000000000..1d11e7f35 --- /dev/null +++ b/lib/ofp-msgs.c @@ -0,0 +1,962 @@ +/* + * 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 *); + +/* 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++); +} + +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); +} + +/* 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; +} + +/* 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(); + } + } + } +} + +/* 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; +} + +/* 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; +} + +/* 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); +} + +/* 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; +} + +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)); + } + } +} diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h new file mode 100644 index 000000000..ed73fc728 --- /dev/null +++ b/lib/ofp-msgs.h @@ -0,0 +1,433 @@ +/* + * 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; + +/* 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); + +/* 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); + +/* OpenFlow message properties. */ +void ofpmsg_update_length(struct ofpbuf *); +const void *ofpmsg_body(const struct ofp_header *); + +/* 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 */ diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 3d3b91938..d1cab7bdc 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -38,6 +38,7 @@ #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" @@ -155,7 +156,7 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh, } 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; @@ -163,7 +164,7 @@ ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo, 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); @@ -485,14 +486,13 @@ ofputil_action_bitmap_to_name(uint32_t bit) } 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; @@ -512,7 +512,7 @@ ofp_print_switch_features(struct ds *string, 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 @@ -668,13 +668,13 @@ ofp10_match_to_string(const struct ofp10_match *om, int verbosity) } 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); @@ -709,14 +709,15 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, } 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; @@ -884,41 +885,38 @@ ofp_print_error(struct ds *string, enum ofperr error) } 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; @@ -936,8 +934,10 @@ ofp_print_port_status(struct ds *string, const struct ofp_port_status *ops) } 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); @@ -952,13 +952,12 @@ ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_desc_stats *ods) } 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; @@ -1037,23 +1036,20 @@ ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh) } 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, @@ -1075,9 +1071,9 @@ 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)); } @@ -1085,14 +1081,25 @@ static void 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 "); @@ -1117,15 +1124,27 @@ static void 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); @@ -1151,9 +1170,10 @@ ofp_print_queue_name(struct ds *string, uint32_t queue_id) } 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); @@ -1165,14 +1185,25 @@ static void 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 "); @@ -1192,7 +1223,7 @@ ofp_print_ofpst_port_desc_reply(struct ds *string, 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); } @@ -1200,22 +1231,19 @@ ofp_print_ofpst_port_desc_reply(struct ds *string, 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]"); @@ -1520,202 +1548,180 @@ ofp_print_version(const struct ofp_header *oh, } 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; } @@ -1737,12 +1743,12 @@ ofp_to_string(const void *oh_, size_t len, int verbosity) 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'); } @@ -1754,12 +1760,12 @@ ofp_to_string(const void *oh_, size_t len, int verbosity) "(***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'); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 8f2217f57..7875cbf86 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -34,6 +34,7 @@ #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" @@ -540,613 +541,6 @@ ofputil_dl_type_from_openflow(ovs_be16 ofp_dl_type) ? 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++); -} - -/* 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; -} /* Protocols. */ @@ -1608,7 +1002,8 @@ ofputil_encode_nx_set_flow_format(enum nx_flow_format nxff) 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; @@ -1664,7 +1059,8 @@ ofputil_make_set_packet_in_format(enum nx_packet_in_format packet_in_format) 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; @@ -1678,7 +1074,8 @@ ofputil_make_flow_mod_table_id(bool flow_mod_table_id) 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; } @@ -1699,15 +1096,14 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, 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; @@ -1744,7 +1140,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, 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; @@ -1810,8 +1206,9 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, 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); @@ -1825,14 +1222,14 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, 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); @@ -1850,7 +1247,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, if (fm->ofpacts) { ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg); } - update_openflow_length(msg); + ofpmsg_update_length(msg); return msg; } @@ -1887,12 +1284,9 @@ ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms, 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); @@ -1904,22 +1298,18 @@ ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr, 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; } @@ -1937,26 +1327,23 @@ enum ofperr 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. */ @@ -1972,15 +1359,18 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, 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); @@ -1991,14 +1381,16 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, 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; @@ -2056,25 +1448,19 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, 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; @@ -2108,7 +1494,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, 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; @@ -2182,10 +1568,11 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, 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); @@ -2207,7 +1594,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, 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; @@ -2238,7 +1625,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, 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 @@ -2246,24 +1633,27 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, 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); @@ -2274,6 +1664,34 @@ ofputil_encode_aggregate_stats_reply( 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. */ @@ -2281,15 +1699,16 @@ enum ofperr 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; @@ -2299,13 +1718,10 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, 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); @@ -2344,8 +1760,9 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, 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); @@ -2363,10 +1780,12 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, 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; @@ -2391,32 +1810,30 @@ enum ofperr 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); @@ -2466,13 +1883,11 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, /* 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; @@ -2485,12 +1900,6 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, 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); @@ -2505,17 +1914,16 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, 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; @@ -2525,7 +1933,7 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, } else { NOT_REACHED(); } - update_openflow_length(packet); + ofpmsg_update_length(packet); return packet; } @@ -2575,12 +1983,19 @@ ofputil_packet_in_reason_from_string(const char *s, * 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 @@ -2590,9 +2005,6 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po, 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; @@ -2799,12 +2211,12 @@ ofputil_append_port_desc_stats_reply(uint8_t ofp_version, 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); } } @@ -2891,29 +2303,33 @@ decode_action_bits(ovs_be32 of_actions, * 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; } @@ -2925,12 +2341,12 @@ ofputil_decode_switch_features(const struct ofp_switch_features *osf, 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 @@ -2943,12 +2359,13 @@ max_ports_in_features(const struct ofp_switch_features *osf) 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; } @@ -2981,15 +2398,20 @@ ofputil_encode_switch_features(const struct ofputil_switch_features *features, { 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); } @@ -3011,9 +2433,9 @@ void 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); } /* ofputil_port_status */ @@ -3021,12 +2443,17 @@ ofputil_put_switch_features_port(const struct ofputil_phy_port *pp, /* 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) { @@ -3034,9 +2461,7 @@ ofputil_decode_port_status(const struct ofp_port_status *ops, } 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; } @@ -3050,13 +2475,17 @@ ofputil_encode_port_status(const struct ofputil_port_status *ps, { 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; } @@ -3068,26 +2497,24 @@ enum ofperr 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; @@ -3098,7 +2525,7 @@ ofputil_decode_port_mod(const struct ofp_header *oh, 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; @@ -3118,7 +2545,8 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm, 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); @@ -3127,7 +2555,8 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm, } 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); @@ -3161,7 +2590,7 @@ ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *rq, if (!msg->l2) { msg->l2 = msg->data; - ofpbuf_pull(msg, sizeof(struct nicira_stats_msg)); + ofpraw_pull_assert(msg); } if (!msg->size) { @@ -3206,9 +2635,7 @@ ofputil_append_flow_monitor_request( 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; @@ -3248,7 +2675,7 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update, if (!msg->l2) { msg->l2 = msg->data; - ofpbuf_pull(msg, sizeof(struct nicira_stats_msg)); + ofpraw_pull_assert(msg); } if (!msg->size) { @@ -3331,7 +2758,9 @@ bad_len: 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 * @@ -3340,7 +2769,8 @@ ofputil_encode_flow_monitor_cancel(uint32_t id) 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; } @@ -3350,10 +2780,8 @@ ofputil_start_flow_update(struct list *replies) { 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); @@ -3398,378 +2826,47 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update, nfuh->length = htons(msg->size - start_ofs); nfuh->event = htons(update->event); - ofputil_postappend_stats_reply(start_ofs, replies); + ofpmp_postappend(replies, start_ofs); } 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; -} -/* 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 @@ -3777,20 +2874,21 @@ make_echo_request(void) 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 * diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 36ae58152..54bec75f6 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -31,85 +31,6 @@ 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); @@ -309,7 +230,10 @@ struct ofputil_aggregate_stats { 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 { @@ -368,7 +292,7 @@ struct ofputil_packet_out { }; 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 *); @@ -473,7 +397,7 @@ struct ofputil_switch_features { 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 *); @@ -495,7 +419,7 @@ struct ofputil_port_status { 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); @@ -556,52 +480,12 @@ void ofputil_append_flow_update(const struct ofputil_flow_update *, 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); diff --git a/lib/rconn.c b/lib/rconn.c index 1129a3b7a..b84cda64d 100644 --- a/lib/rconn.c +++ b/lib/rconn.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <string.h> #include "coverage.h" +#include "ofp-msgs.h" #include "ofp-util.h" #include "ofpbuf.h" #include "openflow/openflow.h" @@ -1121,19 +1122,64 @@ is_connected_state(enum state state) 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 diff --git a/lib/stream.c b/lib/stream.c index 271f16b93..2c7bfc3a5 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -1,5 +1,5 @@ /* - * 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. @@ -778,7 +778,7 @@ stream_guess_content(const uint8_t *data, ssize_t size) return STREAM_SSL; case PAIR('{', '"'): return STREAM_JSONRPC; - case PAIR(OFP10_VERSION, OFPT_HELLO): + case PAIR(OFP10_VERSION, 0 /* OFPT_HELLO */): return STREAM_OPENFLOW; } } diff --git a/lib/vconn.c b/lib/vconn.c index 5cd708d24..8f4052cca 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -28,6 +28,7 @@ #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" @@ -385,7 +386,7 @@ vcs_send_hello(struct vconn *vconn) 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; @@ -406,9 +407,12 @@ vcs_recv_hello(struct vconn *vconn) 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); @@ -529,10 +533,33 @@ vconn_connect(struct vconn *vconn) 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; } @@ -541,40 +568,12 @@ do_recv(struct vconn *vconn, struct ofpbuf **msgp) { 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; } @@ -605,7 +604,8 @@ do_send(struct vconn *vconn, struct ofpbuf *msg) 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); diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c index b70b07085..5ce77c04c 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -26,6 +26,7 @@ #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" @@ -941,15 +942,14 @@ ofconn_send_error(const struct ofconn *ofconn, 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", @@ -1289,7 +1289,7 @@ static void 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); } @@ -1850,8 +1850,8 @@ ofmonitor_flush(struct connmgr *mgr) 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); } } @@ -1861,7 +1861,7 @@ ofmonitor_flush(struct connmgr *mgr) static void ofmonitor_resume(struct ofconn *ofconn) { - struct ofpbuf *resume; + struct ofpbuf *resumed; struct ofmonitor *m; struct list rules; struct list msgs; @@ -1874,9 +1874,9 @@ ofmonitor_resume(struct ofconn *ofconn) 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; diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 4daa0cd77..f61409637 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -34,6 +34,7 @@ #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" @@ -2018,7 +2019,8 @@ handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh) 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; @@ -2031,8 +2033,9 @@ handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh) } 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); @@ -2077,7 +2080,7 @@ reject_slave_controller(struct ofconn *ofconn) } 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; @@ -2096,7 +2099,7 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo) /* 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; } @@ -2182,13 +2185,14 @@ handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh) 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); @@ -2201,15 +2205,14 @@ handle_desc_stats_request(struct ofconn *ofconn, 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; @@ -2248,7 +2251,7 @@ append_port_stat(struct ofport *port, struct list *replies) * 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)); @@ -2267,13 +2270,14 @@ append_port_stat(struct ofport *port, struct list *replies) 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) { @@ -2291,13 +2295,13 @@ handle_port_stats_request(struct ofconn *ofconn, 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), @@ -2487,7 +2491,7 @@ age_secs(long long int age_ms) 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; @@ -2496,7 +2500,7 @@ handle_flow_stats_request(struct ofconn *ofconn, 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; } @@ -2508,7 +2512,7 @@ handle_flow_stats_request(struct ofconn *ofconn, 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; @@ -2633,7 +2637,7 @@ ofproto_port_get_cfm_health(const struct ofproto *ofproto, uint16_t ofp_port) 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; @@ -2644,7 +2648,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn, 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; } @@ -2686,7 +2690,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn, 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; @@ -2703,7 +2707,7 @@ put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id, { 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); @@ -2744,9 +2748,10 @@ handle_queue_stats_for_port(struct ofport *port, uint32_t 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; @@ -2755,7 +2760,7 @@ handle_queue_stats_request(struct ofconn *ofconn, 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); @@ -3289,7 +3294,7 @@ handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn, 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; @@ -3307,7 +3312,8 @@ handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh) 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); @@ -3318,8 +3324,7 @@ static enum ofperr 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); @@ -3332,8 +3337,7 @@ handle_nxt_flow_mod_table_id(struct ofconn *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; @@ -3357,10 +3361,9 @@ static enum ofperr 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; @@ -3379,7 +3382,7 @@ handle_nxt_set_packet_in_format(struct ofconn *ofconn, 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]; @@ -3404,9 +3407,8 @@ static enum ofperr 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; } @@ -3424,7 +3426,9 @@ handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh) 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; } @@ -3594,8 +3598,7 @@ ofmonitor_collect_resume_rules(struct ofmonitor *m, } 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; @@ -3607,7 +3610,7 @@ handle_flow_monitor_request(struct ofconn *ofconn, 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 (;;) { @@ -3646,7 +3649,7 @@ handle_flow_monitor_request(struct ofconn *ofconn, 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); @@ -3682,131 +3685,116 @@ static enum ofperr 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; } } diff --git a/tests/ofp-print.at b/tests/ofp-print.at index 3e9920588..35faaff9f 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -20,7 +20,7 @@ AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print 00bb0008eeff0011], [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 diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index fb57d0c11..300d091a0 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -92,6 +92,7 @@ AT_CHECK([tail -1 stdout], [0], [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]) diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at index e7d6da4d8..658f30e44 100644 --- a/tests/ofproto-macros.at +++ b/tests/ofproto-macros.at @@ -50,7 +50,7 @@ m4_define([OVS_VSWITCHD_START], 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 diff --git a/tests/test-vconn.c b/tests/test-vconn.c index 31451a27e..f37bc38a8 100644 --- a/tests/test-vconn.c +++ b/tests/test-vconn.c @@ -1,5 +1,5 @@ /* - * 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. @@ -22,6 +22,9 @@ #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" @@ -207,8 +210,11 @@ test_read_hello(int argc OVS_UNUSED, char *argv[]) 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 { @@ -274,8 +280,11 @@ test_send_hello(const char *type, const void *out, size_t out_size, 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 { @@ -322,13 +331,12 @@ static void 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 @@ -338,16 +346,15 @@ static void 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 @@ -356,13 +363,12 @@ static void 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, @@ -383,13 +389,13 @@ static void 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[] = { diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 3f64178cb..e9ad18166 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -40,6 +40,7 @@ #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" @@ -393,21 +394,10 @@ open_vconn(const char *name, struct vconn **vconnp) 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"); } @@ -417,7 +407,7 @@ dump_transaction(const char *vconn_name, struct ofpbuf *request) 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); @@ -426,20 +416,26 @@ dump_transaction(const char *vconn_name, struct ofpbuf *request) } 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; @@ -448,16 +444,15 @@ dump_stats_transaction__(struct vconn *vconn, struct ofpbuf *request) 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, @@ -482,10 +477,11 @@ dump_stats_transaction(const char *vconn_name, struct ofpbuf *request) } 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); } @@ -500,7 +496,7 @@ transact_multiple_noreply(struct vconn *vconn, struct list *requests) 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), @@ -531,38 +527,31 @@ static void 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); } @@ -576,8 +565,7 @@ ofctl_show(int argc OVS_UNUSED, char *argv[]) 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); @@ -591,21 +579,22 @@ ofctl_show(int argc OVS_UNUSED, char *argv[]) /* 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 @@ -614,23 +603,24 @@ fetch_port_by_features(const char *vconn_name, 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; @@ -639,13 +629,13 @@ fetch_port_by_features(const char *vconn_name, 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)) { @@ -667,12 +657,10 @@ fetch_port_by_stats(const char *vconn_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); @@ -684,18 +672,21 @@ fetch_port_by_stats(const char *vconn_name, 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 @@ -703,10 +694,7 @@ fetch_port_by_stats(const char *vconn_name, 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; @@ -969,7 +957,8 @@ ofctl_queue_stats(int argc, char *argv[]) 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])); @@ -1318,8 +1307,9 @@ monitor_vconn(struct vconn *vconn) int retval; unixctl_server_run(server); + while (!blocked) { - uint8_t msg_type; + enum ofptype type; retval = vconn_recv(vconn, &b); if (retval == EAGAIN) { @@ -1335,11 +1325,11 @@ monitor_vconn(struct vconn *vconn) 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; } @@ -1430,7 +1420,8 @@ ofctl_dump_ports(int argc, char *argv[]) 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); @@ -1439,7 +1430,7 @@ ofctl_dump_ports(int argc, char *argv[]) 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 @@ -1449,7 +1440,7 @@ ofctl_probe(int argc OVS_UNUSED, char *argv[]) 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)) { @@ -1619,28 +1610,29 @@ ofctl_ping(int argc, char *argv[]) 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); @@ -1675,10 +1667,10 @@ ofctl_benchmark(int argc OVS_UNUSED, char *argv[]) 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); } @@ -1881,18 +1873,16 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid, /* 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)); |