X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fofp-util.c;h=6fe1611e255f76dca0084835df42f99636f26383;hb=fe13b0e71752a5eb30b21e7a09d2f9370bc02387;hp=17b3cc75e862b285d619f1c2b81eb4c48d8555a2;hpb=65120a8a4ec658f4318ca3ac6159e27f584bca8e;p=openvswitch diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 17b3cc75..6fe1611e 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks. + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -271,6 +271,7 @@ alloc_xid(void) 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. */ @@ -281,17 +282,17 @@ struct ofputil_msg_type { /* Represents a malformed OpenFlow message. */ static const struct ofputil_msg_type ofputil_invalid_type = { - OFPUTIL_MSG_INVALID, 0, "OFPUTIL_MSG_INVALID", 0, 0 + 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; - int missing_error; /* ofp_mkerr() value for missing type. */ + enum ofperr missing_error; /* Error value for missing type. */ }; -static int +static enum ofperr ofputil_check_length(const struct ofputil_msg_type *type, unsigned int size) { switch (type->extra_multiple) { @@ -300,7 +301,7 @@ ofputil_check_length(const struct ofputil_msg_type *type, unsigned int size) VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect " "length %u (expected length %u)", type->name, size, type->min_size); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + return OFPERR_OFPBRC_BAD_LEN; } return 0; @@ -309,7 +310,7 @@ ofputil_check_length(const struct ofputil_msg_type *type, unsigned int 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 ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + return OFPERR_OFPBRC_BAD_LEN; } return 0; @@ -321,21 +322,22 @@ ofputil_check_length(const struct ofputil_msg_type *type, unsigned int size) "by an integer multiple of %u bytes)", type->name, size, type->min_size, type->extra_multiple); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + return OFPERR_OFPBRC_BAD_LEN; } return 0; } } -static int +static enum ofperr ofputil_lookup_openflow_message(const struct ofputil_msg_category *cat, - uint32_t value, + 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) { + if (type->value == value + && (!type->ofp_version || version == type->ofp_version)) { *typep = type; return 0; } @@ -346,40 +348,48 @@ ofputil_lookup_openflow_message(const struct ofputil_msg_category *cat, return cat->missing_error; } -static int +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, + { OFPUTIL_NXT_ROLE_REQUEST, OFP10_VERSION, NXT_ROLE_REQUEST, "NXT_ROLE_REQUEST", sizeof(struct nx_role_request), 0 }, - { OFPUTIL_NXT_ROLE_REPLY, + { OFPUTIL_NXT_ROLE_REPLY, OFP10_VERSION, NXT_ROLE_REPLY, "NXT_ROLE_REPLY", sizeof(struct nx_role_request), 0 }, - { OFPUTIL_NXT_SET_FLOW_FORMAT, + { OFPUTIL_NXT_SET_FLOW_FORMAT, OFP10_VERSION, NXT_SET_FLOW_FORMAT, "NXT_SET_FLOW_FORMAT", - sizeof(struct nxt_set_flow_format), 0 }, + sizeof(struct nx_set_flow_format), 0 }, - { OFPUTIL_NXT_FLOW_MOD, + { 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, + { OFPUTIL_NXT_FLOW_REMOVED, OFP10_VERSION, NXT_FLOW_REMOVED, "NXT_FLOW_REMOVED", sizeof(struct nx_flow_removed), 8 }, - { OFPUTIL_NXT_FLOW_MOD_TABLE_ID, + { OFPUTIL_NXT_FLOW_MOD_TABLE_ID, OFP10_VERSION, NXT_FLOW_MOD_TABLE_ID, "NXT_FLOW_MOD_TABLE_ID", - sizeof(struct nxt_flow_mod_table_id), 0 }, + sizeof(struct nx_flow_mod_table_id), 0 }, }; static const struct ofputil_msg_category nxt_category = { "Nicira extension message", nxt_messages, ARRAY_SIZE(nxt_messages), - OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE) + OFPERR_OFPBRC_BAD_SUBTYPE }; const struct ofp_vendor_header *ovh; @@ -389,14 +399,14 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length, if (length == ntohs(oh->length)) { VLOG_WARN_RL(&bad_ofmsg_rl, "truncated vendor message"); } - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + 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 ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR); + return OFPERR_OFPBRC_BAD_VENDOR; } if (length < sizeof(struct nicira_header)) { @@ -406,15 +416,15 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length, ntohs(ovh->header.length), sizeof(struct nicira_header)); } - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + return OFPERR_OFPBRC_BAD_LEN; } nh = (const struct nicira_header *) oh; - return ofputil_lookup_openflow_message(&nxt_category, ntohl(nh->subtype), - typep); + return ofputil_lookup_openflow_message(&nxt_category, oh->version, + ntohl(nh->subtype), typep); } -static int +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; @@ -424,36 +434,36 @@ check_nxstats_msg(const struct ofp_header *oh, size_t length) if (length == ntohs(oh->length)) { VLOG_WARN_RL(&bad_ofmsg_rl, "truncated vendor stats message"); } - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + 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 ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_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 ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + return OFPERR_OFPBRC_BAD_LEN; } return 0; } -static int +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, + { OFPUTIL_NXST_FLOW_REQUEST, OFP10_VERSION, NXST_FLOW, "NXST_FLOW request", sizeof(struct nx_flow_stats_request), 8 }, - { OFPUTIL_NXST_AGGREGATE_REQUEST, + { OFPUTIL_NXST_AGGREGATE_REQUEST, OFP10_VERSION, NXST_AGGREGATE, "NXST_AGGREGATE request", sizeof(struct nx_aggregate_stats_request), 8 }, }; @@ -461,11 +471,11 @@ ofputil_decode_nxst_request(const struct ofp_header *oh, size_t length, static const struct ofputil_msg_category nxst_request_category = { "Nicira extension statistics request", nxst_requests, ARRAY_SIZE(nxst_requests), - OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE) + OFPERR_OFPBRC_BAD_SUBTYPE }; const struct nicira_stats_msg *nsm; - int error; + enum ofperr error; error = check_nxstats_msg(oh, length); if (error) { @@ -473,20 +483,20 @@ ofputil_decode_nxst_request(const struct ofp_header *oh, size_t length, } nsm = (struct nicira_stats_msg *) oh; - return ofputil_lookup_openflow_message(&nxst_request_category, + return ofputil_lookup_openflow_message(&nxst_request_category, oh->version, ntohl(nsm->subtype), typep); } -static int +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, + { OFPUTIL_NXST_FLOW_REPLY, OFP10_VERSION, NXST_FLOW, "NXST_FLOW reply", sizeof(struct nicira_stats_msg), 8 }, - { OFPUTIL_NXST_AGGREGATE_REPLY, + { OFPUTIL_NXST_AGGREGATE_REPLY, OFP10_VERSION, NXST_AGGREGATE, "NXST_AGGREGATE reply", sizeof(struct nx_aggregate_stats_reply), 0 }, }; @@ -494,11 +504,11 @@ ofputil_decode_nxst_reply(const struct ofp_header *oh, size_t length, static const struct ofputil_msg_category nxst_reply_category = { "Nicira extension statistics reply", nxst_replies, ARRAY_SIZE(nxst_replies), - OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE) + OFPERR_OFPBRC_BAD_SUBTYPE }; const struct nicira_stats_msg *nsm; - int error; + enum ofperr error; error = check_nxstats_msg(oh, length); if (error) { @@ -506,53 +516,53 @@ ofputil_decode_nxst_reply(const struct ofp_header *oh, size_t length, } nsm = (struct nicira_stats_msg *) oh; - return ofputil_lookup_openflow_message(&nxst_reply_category, + return ofputil_lookup_openflow_message(&nxst_reply_category, oh->version, ntohl(nsm->subtype), typep); } -static int +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 ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + return OFPERR_OFPBRC_BAD_LEN; } return 0; } -static int +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, + { OFPUTIL_OFPST_DESC_REQUEST, OFP10_VERSION, OFPST_DESC, "OFPST_DESC request", sizeof(struct ofp_stats_msg), 0 }, - { OFPUTIL_OFPST_FLOW_REQUEST, + { OFPUTIL_OFPST_FLOW_REQUEST, OFP10_VERSION, OFPST_FLOW, "OFPST_FLOW request", sizeof(struct ofp_flow_stats_request), 0 }, - { OFPUTIL_OFPST_AGGREGATE_REQUEST, + { OFPUTIL_OFPST_AGGREGATE_REQUEST, OFP10_VERSION, OFPST_AGGREGATE, "OFPST_AGGREGATE request", sizeof(struct ofp_flow_stats_request), 0 }, - { OFPUTIL_OFPST_TABLE_REQUEST, + { OFPUTIL_OFPST_TABLE_REQUEST, OFP10_VERSION, OFPST_TABLE, "OFPST_TABLE request", sizeof(struct ofp_stats_msg), 0 }, - { OFPUTIL_OFPST_PORT_REQUEST, + { OFPUTIL_OFPST_PORT_REQUEST, OFP10_VERSION, OFPST_PORT, "OFPST_PORT request", sizeof(struct ofp_port_stats_request), 0 }, - { OFPUTIL_OFPST_QUEUE_REQUEST, + { OFPUTIL_OFPST_QUEUE_REQUEST, OFP10_VERSION, OFPST_QUEUE, "OFPST_QUEUE request", sizeof(struct ofp_queue_stats_request), 0 }, - { 0, + { 0, 0, OFPST_VENDOR, "OFPST_VENDOR request", sizeof(struct ofp_vendor_stats_msg), 1 }, }; @@ -560,11 +570,11 @@ ofputil_decode_ofpst_request(const struct ofp_header *oh, size_t length, static const struct ofputil_msg_category ofpst_request_category = { "OpenFlow statistics", ofpst_requests, ARRAY_SIZE(ofpst_requests), - OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT) + OFPERR_OFPBRC_BAD_STAT }; const struct ofp_stats_msg *request = (const struct ofp_stats_msg *) oh; - int error; + enum ofperr error; error = check_stats_msg(oh, length); if (error) { @@ -572,43 +582,44 @@ ofputil_decode_ofpst_request(const struct ofp_header *oh, size_t length, } error = ofputil_lookup_openflow_message(&ofpst_request_category, - ntohs(request->type), typep); + oh->version, ntohs(request->type), + typep); if (!error && request->type == htons(OFPST_VENDOR)) { error = ofputil_decode_nxst_request(oh, length, typep); } return error; } -static int +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, + { OFPUTIL_OFPST_DESC_REPLY, OFP10_VERSION, OFPST_DESC, "OFPST_DESC reply", sizeof(struct ofp_desc_stats), 0 }, - { OFPUTIL_OFPST_FLOW_REPLY, + { OFPUTIL_OFPST_FLOW_REPLY, OFP10_VERSION, OFPST_FLOW, "OFPST_FLOW reply", sizeof(struct ofp_stats_msg), 1 }, - { OFPUTIL_OFPST_AGGREGATE_REPLY, + { OFPUTIL_OFPST_AGGREGATE_REPLY, OFP10_VERSION, OFPST_AGGREGATE, "OFPST_AGGREGATE reply", sizeof(struct ofp_aggregate_stats_reply), 0 }, - { OFPUTIL_OFPST_TABLE_REPLY, + { 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, + { 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, + { OFPUTIL_OFPST_QUEUE_REPLY, OFP10_VERSION, OFPST_QUEUE, "OFPST_QUEUE reply", sizeof(struct ofp_stats_msg), sizeof(struct ofp_queue_stats) }, - { 0, + { 0, 0, OFPST_VENDOR, "OFPST_VENDOR reply", sizeof(struct ofp_vendor_stats_msg), 1 }, }; @@ -616,18 +627,18 @@ ofputil_decode_ofpst_reply(const struct ofp_header *oh, size_t length, static const struct ofputil_msg_category ofpst_reply_category = { "OpenFlow statistics", ofpst_replies, ARRAY_SIZE(ofpst_replies), - OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT) + OFPERR_OFPBRC_BAD_STAT }; const struct ofp_stats_msg *reply = (const struct ofp_stats_msg *) oh; - int error; + enum ofperr error; error = check_stats_msg(oh, length); if (error) { return error; } - error = ofputil_lookup_openflow_message(&ofpst_reply_category, + 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); @@ -635,88 +646,88 @@ ofputil_decode_ofpst_reply(const struct ofp_header *oh, size_t length, return error; } -static int +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, + { OFPUTIL_OFPT_HELLO, OFP10_VERSION, OFPT_HELLO, "OFPT_HELLO", sizeof(struct ofp_hello), 1 }, - { OFPUTIL_OFPT_ERROR, + { OFPUTIL_OFPT_ERROR, 0, OFPT_ERROR, "OFPT_ERROR", sizeof(struct ofp_error_msg), 1 }, - { OFPUTIL_OFPT_ECHO_REQUEST, + { OFPUTIL_OFPT_ECHO_REQUEST, OFP10_VERSION, OFPT_ECHO_REQUEST, "OFPT_ECHO_REQUEST", sizeof(struct ofp_header), 1 }, - { OFPUTIL_OFPT_ECHO_REPLY, + { OFPUTIL_OFPT_ECHO_REPLY, OFP10_VERSION, OFPT_ECHO_REPLY, "OFPT_ECHO_REPLY", sizeof(struct ofp_header), 1 }, - { OFPUTIL_OFPT_FEATURES_REQUEST, + { OFPUTIL_OFPT_FEATURES_REQUEST, OFP10_VERSION, OFPT_FEATURES_REQUEST, "OFPT_FEATURES_REQUEST", sizeof(struct ofp_header), 0 }, - { OFPUTIL_OFPT_FEATURES_REPLY, + { OFPUTIL_OFPT_FEATURES_REPLY, OFP10_VERSION, OFPT_FEATURES_REPLY, "OFPT_FEATURES_REPLY", sizeof(struct ofp_switch_features), sizeof(struct ofp_phy_port) }, - { OFPUTIL_OFPT_GET_CONFIG_REQUEST, + { 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, + { 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, + { OFPUTIL_OFPT_SET_CONFIG, OFP10_VERSION, OFPT_SET_CONFIG, "OFPT_SET_CONFIG", sizeof(struct ofp_switch_config), 0 }, - { OFPUTIL_OFPT_PACKET_IN, + { OFPUTIL_OFPT_PACKET_IN, OFP10_VERSION, OFPT_PACKET_IN, "OFPT_PACKET_IN", offsetof(struct ofp_packet_in, data), 1 }, - { OFPUTIL_OFPT_FLOW_REMOVED, + { OFPUTIL_OFPT_FLOW_REMOVED, OFP10_VERSION, OFPT_FLOW_REMOVED, "OFPT_FLOW_REMOVED", sizeof(struct ofp_flow_removed), 0 }, - { OFPUTIL_OFPT_PORT_STATUS, + { OFPUTIL_OFPT_PORT_STATUS, OFP10_VERSION, OFPT_PORT_STATUS, "OFPT_PORT_STATUS", sizeof(struct ofp_port_status), 0 }, - { OFPUTIL_OFPT_PACKET_OUT, + { OFPUTIL_OFPT_PACKET_OUT, OFP10_VERSION, OFPT_PACKET_OUT, "OFPT_PACKET_OUT", sizeof(struct ofp_packet_out), 1 }, - { OFPUTIL_OFPT_FLOW_MOD, + { OFPUTIL_OFPT_FLOW_MOD, OFP10_VERSION, OFPT_FLOW_MOD, "OFPT_FLOW_MOD", sizeof(struct ofp_flow_mod), 1 }, - { OFPUTIL_OFPT_PORT_MOD, + { OFPUTIL_OFPT_PORT_MOD, OFP10_VERSION, OFPT_PORT_MOD, "OFPT_PORT_MOD", sizeof(struct ofp_port_mod), 0 }, - { 0, + { 0, OFP10_VERSION, OFPT_STATS_REQUEST, "OFPT_STATS_REQUEST", sizeof(struct ofp_stats_msg), 1 }, - { 0, + { 0, OFP10_VERSION, OFPT_STATS_REPLY, "OFPT_STATS_REPLY", sizeof(struct ofp_stats_msg), 1 }, - { OFPUTIL_OFPT_BARRIER_REQUEST, + { OFPUTIL_OFPT_BARRIER_REQUEST, OFP10_VERSION, OFPT_BARRIER_REQUEST, "OFPT_BARRIER_REQUEST", sizeof(struct ofp_header), 0 }, - { OFPUTIL_OFPT_BARRIER_REPLY, + { OFPUTIL_OFPT_BARRIER_REPLY, OFP10_VERSION, OFPT_BARRIER_REPLY, "OFPT_BARRIER_REPLY", sizeof(struct ofp_header), 0 }, - { 0, + { 0, 0, OFPT_VENDOR, "OFPT_VENDOR", sizeof(struct ofp_vendor_header), 1 }, }; @@ -724,12 +735,13 @@ ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length, static const struct ofputil_msg_category ofpt_category = { "OpenFlow message", ofpt_messages, ARRAY_SIZE(ofpt_messages), - OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE) + OFPERR_OFPBRC_BAD_TYPE }; - int error; + enum ofperr error; - error = ofputil_lookup_openflow_message(&ofpt_category, oh->type, typep); + error = ofputil_lookup_openflow_message(&ofpt_category, oh->version, + oh->type, typep); if (!error) { switch (oh->type) { case OFPT_VENDOR: @@ -750,22 +762,21 @@ ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length, return error; } -/* Decodes the message type represented by 'oh'. Returns 0 if successful or - * an OpenFlow error code constructed with ofp_mkerr() on failure. Either - * way, stores in '*typep' a type structure that can be inspected with the - * ofputil_msg_type_*() functions. +/* 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. */ -int +enum ofperr ofputil_decode_msg_type(const struct ofp_header *oh, const struct ofputil_msg_type **typep) { size_t length = ntohs(oh->length); - int error; + enum ofperr error; error = ofputil_decode_msg_type__(oh, length, typep); if (!error) { @@ -779,18 +790,17 @@ ofputil_decode_msg_type(const struct ofp_header *oh, /* 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 constructed with ofp_mkerr() on failure. Either way, stores in - * '*typep' a type structure that can be inspected with the - * ofputil_msg_type_*() functions. */ -int + * 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) { - int error; + enum ofperr error; error = (length >= sizeof *oh ? ofputil_decode_msg_type__(oh, length, typep) - : ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN)); + : OFPERR_OFPBRC_BAD_LEN); if (error) { *typep = &ofputil_invalid_type; } @@ -839,6 +849,39 @@ ofputil_flow_format_from_string(const char *s) : -1); } +bool +ofputil_packet_in_format_is_valid(enum nx_packet_in_format packet_in_format) +{ + switch (packet_in_format) { + case NXPIF_OPENFLOW10: + case NXPIF_NXM: + return true; + } + + return false; +} + +const char * +ofputil_packet_in_format_to_string(enum nx_packet_in_format packet_in_format) +{ + switch (packet_in_format) { + case NXPIF_OPENFLOW10: + return "openflow10"; + case NXPIF_NXM: + return "nxm"; + default: + NOT_REACHED(); + } +} + +int +ofputil_packet_in_format_from_string(const char *s) +{ + return (!strcmp(s, "openflow10") ? NXPIF_OPENFLOW10 + : !strcmp(s, "nxm") ? NXPIF_NXM + : -1); +} + static bool regs_fully_wildcarded(const struct flow_wildcards *wc) { @@ -918,7 +961,7 @@ ofputil_min_flow_format(const struct cls_rule *rule) struct ofpbuf * ofputil_make_set_flow_format(enum nx_flow_format flow_format) { - struct nxt_set_flow_format *sff; + struct nx_set_flow_format *sff; struct ofpbuf *msg; sff = make_nxmsg(sizeof *sff, NXT_SET_FLOW_FORMAT, &msg); @@ -927,12 +970,24 @@ ofputil_make_set_flow_format(enum nx_flow_format flow_format) return msg; } +struct ofpbuf * +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); + spif->format = htonl(packet_in_format); + + return msg; +} + /* Returns an OpenFlow message that can be used to turn the flow_mod_table_id * extension on or off (according to 'flow_mod_table_id'). */ struct ofpbuf * ofputil_make_flow_mod_table_id(bool flow_mod_table_id) { - struct nxt_flow_mod_table_id *nfmti; + struct nx_flow_mod_table_id *nfmti; struct ofpbuf *msg; nfmti = make_nxmsg(sizeof *nfmti, NXT_FLOW_MOD_TABLE_ID, &msg); @@ -948,7 +1003,7 @@ ofputil_make_flow_mod_table_id(bool flow_mod_table_id) * enabled, false otherwise. * * Does not validate the flow_mod actions. */ -int +enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, const struct ofp_header *oh, bool flow_mod_table_id) { @@ -963,7 +1018,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, /* Standard OpenFlow flow_mod. */ const struct ofp_flow_mod *ofm; uint16_t priority; - int error; + enum ofperr error; /* Dissect the message. */ ofm = ofpbuf_pull(&b, sizeof *ofm); @@ -997,7 +1052,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, } else if (ofputil_msg_type_code(type) == OFPUTIL_NXT_FLOW_MOD) { /* Nicira extended flow_mod. */ const struct nx_flow_mod *nfm; - int error; + enum ofperr error; /* Dissect the message. */ nfm = ofpbuf_pull(&b, sizeof *nfm); @@ -1018,7 +1073,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, /* The "NXM_NX_COOKIE*" matches are not valid for flow * additions. Additions must use the "cookie" field of * the "nx_flow_mod" structure. */ - return ofp_mkerr(OFPET_BAD_REQUEST, NXBRC_NXM_INVALID); + return OFPERR_NXBRC_NXM_INVALID; } else { fm->cookie = nfm->cookie; fm->cookie_mask = htonll(UINT64_MAX); @@ -1108,7 +1163,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, return msg; } -static int +static enum ofperr ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr, const struct ofp_header *oh, bool aggregate) @@ -1125,14 +1180,14 @@ ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr, return 0; } -static int +static enum ofperr ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr, const struct ofp_header *oh, bool aggregate) { const struct nx_flow_stats_request *nfsr; struct ofpbuf b; - int error; + enum ofperr error; ofpbuf_use_const(&b, oh, ntohs(oh->length)); @@ -1143,7 +1198,7 @@ ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr, return error; } if (b.size) { - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + return OFPERR_OFPBRC_BAD_LEN; } fsr->aggregate = aggregate; @@ -1156,7 +1211,7 @@ ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr, /* Converts an OFPST_FLOW, OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE * request 'oh', into an abstract flow_stats_request in 'fsr'. Returns 0 if * successful, otherwise an OpenFlow error code. */ -int +enum ofperr ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr, const struct ofp_header *oh) { @@ -1442,7 +1497,7 @@ ofputil_encode_aggregate_stats_reply( /* 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. */ -int +enum ofperr ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, const struct ofp_header *oh) { @@ -1478,7 +1533,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, return error; } if (b.size) { - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + return OFPERR_OFPBRC_BAD_LEN; } fr->cookie = nfr->cookie; @@ -1560,10 +1615,46 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, pin->packet_len = ntohs(opi->header.length) - offsetof(struct ofp_packet_in, data); - pin->in_port = ntohs(opi->in_port); + 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) { + 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); + if (error) { + return error; + } + + if (!ofpbuf_try_pull(&b, 2)) { + return OFPERR_OFPBRC_BAD_LEN; + } + + pin->packet = b.data; + pin->packet_len = b.size; + pin->reason = npi->reason; + pin->table_id = npi->table_id; + pin->cookie = npi->cookie; + + pin->fmd.in_port = rule.flow.in_port; + + pin->fmd.tun_id = rule.flow.tun_id; + pin->fmd.tun_id_mask = rule.wc.tun_id_mask; + + memcpy(pin->fmd.regs, rule.flow.regs, sizeof pin->fmd.regs); + memcpy(pin->fmd.reg_masks, rule.wc.reg_masks, + sizeof pin->fmd.reg_masks); + + pin->buffer_id = ntohl(npi->buffer_id); + pin->total_len = ntohs(npi->total_len); } else { NOT_REACHED(); } @@ -1571,30 +1662,76 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, return 0; } -/* Converts abstract ofputil_packet_in 'pin' into an OFPT_PACKET_IN message - * and returns the message. */ +/* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message + * in the format specified by 'packet_in_format'. */ struct ofpbuf * -ofputil_encode_packet_in(const struct ofputil_packet_in *pin) +ofputil_encode_packet_in(const struct ofputil_packet_in *pin, + enum nx_packet_in_format packet_in_format) { - struct ofp_packet_in opi; - struct ofpbuf *rw_packet; - - rw_packet = ofpbuf_clone_data_with_headroom( - pin->packet, MIN(pin->send_len, pin->packet_len), - offsetof(struct ofp_packet_in, data)); + size_t send_len = MIN(pin->send_len, pin->packet_len); + struct ofpbuf *packet; /* Add OFPT_PACKET_IN. */ - memset(&opi, 0, sizeof opi); - opi.header.version = OFP_VERSION; - opi.header.type = OFPT_PACKET_IN; - opi.total_len = htons(pin->packet_len); - opi.in_port = htons(pin->in_port); - opi.reason = pin->reason; - opi.buffer_id = htonl(pin->buffer_id); - ofpbuf_push(rw_packet, &opi, offsetof(struct ofp_packet_in, data)); - update_openflow_length(rw_packet); + 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 = OFP_VERSION; + opi->header.type = OFPT_PACKET_IN; + opi->total_len = htons(pin->total_len); + opi->in_port = htons(pin->fmd.in_port); + opi->reason = pin->reason; + opi->buffer_id = htonl(pin->buffer_id); + + ofpbuf_put(packet, pin->packet, send_len); + } else if (packet_in_format == NXPIF_NXM) { + struct nx_packet_in *npi; + struct cls_rule rule; + 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); + + for (i = 0; i < FLOW_N_REGS; i++) { + cls_rule_set_reg_masked(&rule, i, pin->fmd.regs[i], + pin->fmd.reg_masks[i]); + } + + cls_rule_set_in_port(&rule, pin->fmd.in_port); + + ofpbuf_put_zeros(packet, sizeof *npi); + match_len = nx_put_match(packet, &rule, 0, 0); + ofpbuf_put_zeros(packet, 2); + ofpbuf_put(packet, pin->packet, send_len); + + npi = packet->data; + npi->nxh.header.version = OFP_VERSION; + npi->nxh.header.type = OFPT_VENDOR; + npi->nxh.vendor = htonl(NX_VENDOR_ID); + npi->nxh.subtype = htonl(NXT_PACKET_IN); + + npi->buffer_id = htonl(pin->buffer_id); + npi->total_len = htons(pin->total_len); + npi->reason = pin->reason; + npi->table_id = pin->table_id; + npi->cookie = pin->cookie; + npi->match_len = htons(match_len); + } else { + NOT_REACHED(); + } + update_openflow_length(packet); - return rw_packet; + return packet; } /* Returns a string representing the message type of 'type'. The string is the @@ -2086,8 +2223,8 @@ ofputil_frag_handling_from_string(const char *s, enum ofp_config_flags *flags) /* Checks that 'port' is a valid output port for the OFPAT_OUTPUT action, given * that the switch will never have more than 'max_ports' ports. Returns 0 if - * 'port' is valid, otherwise an ofp_mkerr() return code. */ -int + * 'port' is valid, otherwise an OpenFlow return code. */ +enum ofperr ofputil_check_output_port(uint16_t port, int max_ports) { switch (port) { @@ -2104,7 +2241,7 @@ ofputil_check_output_port(uint16_t port, int max_ports) if (port < max_ports) { return 0; } - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT); + return OFPERR_OFPBAC_BAD_OUT_PORT; } } @@ -2170,16 +2307,16 @@ ofputil_format_port(uint16_t port, struct ds *s) ds_put_cstr(s, name); } -static int +static enum ofperr check_resubmit_table(const struct nx_action_resubmit *nar) { if (nar->pad[0] || nar->pad[1] || nar->pad[2]) { - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + return OFPERR_OFPBAC_BAD_ARGUMENT; } return 0; } -static int +static enum ofperr check_output_reg(const struct nx_action_output_reg *naor, const struct flow *flow) { @@ -2187,7 +2324,7 @@ check_output_reg(const struct nx_action_output_reg *naor, for (i = 0; i < sizeof naor->zero; i++) { if (naor->zero[i]) { - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + return OFPERR_OFPBAC_BAD_ARGUMENT; } } @@ -2195,7 +2332,7 @@ check_output_reg(const struct nx_action_output_reg *naor, nxm_decode_n_bits(naor->ofs_nbits), flow); } -int +enum ofperr validate_actions(const union ofp_action *actions, size_t n_actions, const struct flow *flow, int max_ports) { @@ -2203,20 +2340,16 @@ validate_actions(const union ofp_action *actions, size_t n_actions, size_t left; OFPUTIL_ACTION_FOR_EACH (a, left, actions, n_actions) { + enum ofperr error; uint16_t port; - int error; int code; code = ofputil_decode_action(a); if (code < 0) { - char *msg; - error = -code; - msg = ofputil_error_to_string(error); VLOG_WARN_RL(&bad_ofmsg_rl, "action decoding error at offset %td (%s)", - (a - actions) * sizeof *a, msg); - free(msg); + (a - actions) * sizeof *a, ofperr_get_name(error)); return error; } @@ -2230,13 +2363,13 @@ validate_actions(const union ofp_action *actions, size_t n_actions, case OFPUTIL_OFPAT_SET_VLAN_VID: if (a->vlan_vid.vlan_vid & ~htons(0xfff)) { - error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + error = OFPERR_OFPBAC_BAD_ARGUMENT; } break; case OFPUTIL_OFPAT_SET_VLAN_PCP: if (a->vlan_pcp.vlan_pcp & ~7) { - error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + error = OFPERR_OFPBAC_BAD_ARGUMENT; } break; @@ -2244,7 +2377,7 @@ validate_actions(const union ofp_action *actions, size_t n_actions, port = ntohs(((const struct ofp_action_enqueue *) a)->port); if (port >= max_ports && port != OFPP_IN_PORT && port != OFPP_LOCAL) { - error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT); + error = OFPERR_OFPBAC_BAD_OUT_PORT; } break; @@ -2303,21 +2436,20 @@ validate_actions(const union ofp_action *actions, size_t n_actions, case OFPUTIL_NXAST_NOTE: case OFPUTIL_NXAST_SET_TUNNEL64: case OFPUTIL_NXAST_EXIT: + case OFPUTIL_NXAST_DEC_TTL: break; } if (error) { - char *msg = ofputil_error_to_string(error); VLOG_WARN_RL(&bad_ofmsg_rl, "bad action at offset %td (%s)", - (a - actions) * sizeof *a, msg); - free(msg); + (a - actions) * sizeof *a, ofperr_get_name(error)); return error; } } if (left) { VLOG_WARN_RL(&bad_ofmsg_rl, "bad action format at offset %zu", (n_actions - left) * sizeof *a); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + return OFPERR_OFPBAC_BAD_LEN; } return 0; } @@ -2329,11 +2461,11 @@ struct ofputil_action { }; static const struct ofputil_action action_bad_type - = { -OFP_MKERR(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE), 0, UINT_MAX }; + = { -OFPERR_OFPBAC_BAD_TYPE, 0, UINT_MAX }; static const struct ofputil_action action_bad_len - = { -OFP_MKERR(OFPET_BAD_ACTION, OFPBAC_BAD_LEN), 0, UINT_MAX }; + = { -OFPERR_OFPBAC_BAD_LEN, 0, UINT_MAX }; static const struct ofputil_action action_bad_vendor - = { -OFP_MKERR(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR), 0, UINT_MAX }; + = { -OFPERR_OFPBAC_BAD_VENDOR, 0, UINT_MAX }; static const struct ofputil_action * ofputil_decode_ofpat_action(const union ofp_action *a) @@ -2384,8 +2516,8 @@ ofputil_decode_nxast_action(const union ofp_action *a) } /* Parses 'a' to determine its type. Returns a nonnegative OFPUTIL_OFPAT_* or - * OFPUTIL_NXAST_* constant if successful, otherwise a negative OpenFlow error - * code (as returned by ofp_mkerr()). + * OFPUTIL_NXAST_* constant if successful, otherwise a negative OFPERR_* error + * code. * * The caller must have already verified that 'a''s length is correct (that is, * a->header.len is nonzero and a multiple of sizeof(union ofp_action) and no @@ -2405,7 +2537,7 @@ ofputil_decode_action(const union ofp_action *a) switch (ntohl(a->vendor.vendor)) { case NX_VENDOR_ID: if (len < sizeof(struct nx_action_header)) { - return -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + return -OFPERR_OFPBAC_BAD_LEN; } action = ofputil_decode_nxast_action(a); break; @@ -2417,7 +2549,7 @@ ofputil_decode_action(const union ofp_action *a) return (len >= action->min_len && len <= action->max_len ? action->code - : -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN)); + : -OFPERR_OFPBAC_BAD_LEN); } /* Parses 'a' and returns its type as an OFPUTIL_OFPAT_* or OFPUTIL_NXAST_* @@ -2644,207 +2776,6 @@ ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format) } } -static uint32_t -vendor_code_to_id(uint8_t code) -{ - switch (code) { -#define OFPUTIL_VENDOR(NAME, VENDOR_ID) case NAME: return VENDOR_ID; - OFPUTIL_VENDORS -#undef OFPUTIL_VENDOR - default: - return UINT32_MAX; - } -} - -static int -vendor_id_to_code(uint32_t id) -{ - switch (id) { -#define OFPUTIL_VENDOR(NAME, VENDOR_ID) case VENDOR_ID: return NAME; - OFPUTIL_VENDORS -#undef OFPUTIL_VENDOR - default: - return -1; - } -} - -/* Creates and returns an OpenFlow message of type OFPT_ERROR with the error - * information taken from 'error', whose encoding must be as described in the - * large comment in ofp-util.h. If 'oh' is nonnull, then the error will use - * oh->xid as its transaction ID, and it will include up to the first 64 bytes - * of 'oh'. - * - * Returns NULL if 'error' is not an OpenFlow error code. */ -struct ofpbuf * -ofputil_encode_error_msg(int error, const struct ofp_header *oh) -{ - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - - struct ofpbuf *buf; - const void *data; - size_t len; - uint8_t vendor; - uint16_t type; - uint16_t code; - ovs_be32 xid; - - if (!is_ofp_error(error)) { - /* We format 'error' with strerror() here since it seems likely to be - * a system errno value. */ - VLOG_WARN_RL(&rl, "invalid OpenFlow error code %d (%s)", - error, strerror(error)); - return NULL; - } - - if (oh) { - xid = oh->xid; - data = oh; - len = ntohs(oh->length); - if (len > 64) { - len = 64; - } - } else { - xid = 0; - data = NULL; - len = 0; - } - - vendor = get_ofp_err_vendor(error); - type = get_ofp_err_type(error); - code = get_ofp_err_code(error); - if (vendor == OFPUTIL_VENDOR_OPENFLOW) { - struct ofp_error_msg *oem; - - oem = make_openflow_xid(len + sizeof *oem, OFPT_ERROR, xid, &buf); - oem->type = htons(type); - oem->code = htons(code); - } else { - struct ofp_error_msg *oem; - struct nx_vendor_error *nve; - uint32_t vendor_id; - - vendor_id = vendor_code_to_id(vendor); - if (vendor_id == UINT32_MAX) { - VLOG_WARN_RL(&rl, "error %x contains invalid vendor code %d", - error, vendor); - return NULL; - } - - oem = make_openflow_xid(len + sizeof *oem + sizeof *nve, - OFPT_ERROR, xid, &buf); - oem->type = htons(NXET_VENDOR); - oem->code = htons(NXVC_VENDOR_ERROR); - - nve = (struct nx_vendor_error *)oem->data; - nve->vendor = htonl(vendor_id); - nve->type = htons(type); - nve->code = htons(code); - } - - if (len) { - buf->size -= len; - ofpbuf_put(buf, data, len); - } - - return buf; -} - -/* Decodes 'oh', which should be an OpenFlow OFPT_ERROR message, and returns an - * Open vSwitch internal error code in the format described in the large - * comment in ofp-util.h. - * - * 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. */ -int -ofputil_decode_error_msg(const struct ofp_header *oh, size_t *payload_ofs) -{ - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - - const struct ofp_error_msg *oem; - uint16_t type, code; - struct ofpbuf b; - int vendor; - - if (payload_ofs) { - *payload_ofs = 0; - } - if (oh->type != OFPT_ERROR) { - return EPROTO; - } - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - oem = ofpbuf_try_pull(&b, sizeof *oem); - if (!oem) { - return EPROTO; - } - - type = ntohs(oem->type); - code = ntohs(oem->code); - if (type == NXET_VENDOR && code == NXVC_VENDOR_ERROR) { - const struct nx_vendor_error *nve = ofpbuf_try_pull(&b, sizeof *nve); - if (!nve) { - return EPROTO; - } - - vendor = vendor_id_to_code(ntohl(nve->vendor)); - if (vendor < 0) { - VLOG_WARN_RL(&rl, "error contains unknown vendor ID %#"PRIx32, - ntohl(nve->vendor)); - return EPROTO; - } - type = ntohs(nve->type); - code = ntohs(nve->code); - } else { - vendor = OFPUTIL_VENDOR_OPENFLOW; - } - - if (type >= 1024) { - VLOG_WARN_RL(&rl, "error contains type %"PRIu16" greater than " - "supported maximum value 1023", type); - return EPROTO; - } - - if (payload_ofs) { - *payload_ofs = (uint8_t *) b.data - (uint8_t *) oh; - } - return ofp_mkerr_vendor(vendor, type, code); -} - -void -ofputil_format_error(struct ds *s, int error) -{ - if (is_errno(error)) { - ds_put_cstr(s, strerror(error)); - } else { - uint16_t type = get_ofp_err_type(error); - uint16_t code = get_ofp_err_code(error); - const char *type_s = ofp_error_type_to_string(type); - const char *code_s = ofp_error_code_to_string(type, code); - - ds_put_format(s, "type "); - if (type_s) { - ds_put_cstr(s, type_s); - } else { - ds_put_format(s, "%"PRIu16, type); - } - - ds_put_cstr(s, ", code "); - if (code_s) { - ds_put_cstr(s, code_s); - } else { - ds_put_format(s, "%"PRIu16, code); - } - } -} - -char * -ofputil_error_to_string(int error) -{ - struct ds s = DS_EMPTY_INITIALIZER; - ofputil_format_error(&s, error); - return ds_steal_cstr(&s); -} - /* Attempts to pull 'actions_len' bytes from the front of 'b'. Returns 0 if * successful, otherwise an OpenFlow error. * @@ -2856,7 +2787,7 @@ ofputil_error_to_string(int error) * do so, with validate_actions()). The caller is also responsible for making * sure that 'b->data' is initially aligned appropriately for "union * ofp_action". */ -int +enum ofperr ofputil_pull_actions(struct ofpbuf *b, unsigned int actions_len, union ofp_action **actionsp, size_t *n_actionsp) { @@ -2880,7 +2811,7 @@ ofputil_pull_actions(struct ofpbuf *b, unsigned int actions_len, error: *actionsp = NULL; *n_actionsp = 0; - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + return OFPERR_OFPBRC_BAD_LEN; } bool