X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fofp-util.c;h=c9346a50d08f7663c7292f3233c50bb6654bfb47;hb=d91cf14f5bdab1e513fc3520649e38f3617ac3b9;hp=0ad23c7de6d760d3d8cbba1f42f074c6593c279b;hpb=969fc56c2abb0c3a1bf0225032250aa537df55a3;p=openvswitch diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 0ad23c7d..c9346a50 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -32,7 +32,9 @@ #include "multipath.h" #include "netdev.h" #include "nx-match.h" +#include "ofp-actions.h" #include "ofp-errors.h" +#include "ofp-msgs.h" #include "ofp-util.h" #include "ofpbuf.h" #include "packets.h" @@ -103,15 +105,14 @@ static const flow_wildcards_t WC_INVARIANTS = 0 void ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 14); /* Initialize most of rule->wc. */ flow_wildcards_init_catchall(wc); wc->wildcards = (OVS_FORCE flow_wildcards_t) ofpfw & WC_INVARIANTS; /* Wildcard fields that aren't defined by ofp10_match or tun_id. */ - wc->wildcards |= (FWW_ARP_SHA | FWW_ARP_THA | FWW_NW_ECN | FWW_NW_TTL - | FWW_IPV6_LABEL); + wc->wildcards |= FWW_NW_ECN | FWW_NW_TTL; if (ofpfw & OFPFW10_NW_TOS) { /* OpenFlow 1.0 defines a TOS wildcard, but it's much later in @@ -170,7 +171,8 @@ ofputil_cls_rule_from_ofp10_match(const struct ofp10_match *match, rule->flow.nw_proto = match->nw_proto; /* Translate VLANs. */ - if (!(ofpfw & OFPFW10_DL_VLAN) && match->dl_vlan == htons(OFP_VLAN_NONE)) { + if (!(ofpfw & OFPFW10_DL_VLAN) && + match->dl_vlan == htons(OFP10_VLAN_NONE)) { /* Match only packets without 802.1Q header. * * When OFPFW10_DL_VLAN_PCP is wildcarded, this is obviously correct. @@ -231,7 +233,8 @@ ofputil_cls_rule_to_ofp10_match(const struct cls_rule *rule, ofpfw |= OFPFW10_DL_VLAN | OFPFW10_DL_VLAN_PCP; } else if (rule->wc.vlan_tci_mask & htons(VLAN_CFI) && !(rule->flow.vlan_tci & htons(VLAN_CFI))) { - match->dl_vlan = htons(OFP_VLAN_NONE); + match->dl_vlan = htons(OFP10_VLAN_NONE); + ofpfw |= OFPFW10_DL_VLAN_PCP; } else { if (!(rule->wc.vlan_tci_mask & htons(VLAN_VID_MASK))) { ofpfw |= OFPFW10_DL_VLAN; @@ -538,593 +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 }, - }; - - 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 }, - }; - - 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 }, - }; - - 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, - OFPT10_PACKET_OUT, "OFPT_PACKET_OUT", - sizeof(struct ofp_packet_out), 1 }, - - { OFPUTIL_OFPT_FLOW_MOD, OFP10_VERSION, - OFPT10_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. */ @@ -1158,12 +574,13 @@ ofputil_protocol_from_ofp_version(int version) { switch (version) { case OFP10_VERSION: return OFPUTIL_P_OF10; + case OFP12_VERSION: return OFPUTIL_P_OF12; default: return 0; } } -/* Returns the OpenFlow protocol version number (e.g. OFP10_VERSION or - * OFP11_VERSION) that corresponds to 'protocol'. */ +/* Returns the OpenFlow protocol version number (e.g. OFP10_VERSION, + * OFP11_VERSION or OFP12_VERSION) that corresponds to 'protocol'. */ uint8_t ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol) { @@ -1173,6 +590,8 @@ ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol) case OFPUTIL_P_NXM: case OFPUTIL_P_NXM_TID: return OFP10_VERSION; + case OFPUTIL_P_OF12: + return OFP12_VERSION; } NOT_REACHED(); @@ -1208,6 +627,9 @@ ofputil_protocol_set_tid(enum ofputil_protocol protocol, bool enable) case OFPUTIL_P_NXM_TID: return enable ? OFPUTIL_P_NXM_TID : OFPUTIL_P_NXM; + case OFPUTIL_P_OF12: + return OFPUTIL_P_OF12; + default: NOT_REACHED(); } @@ -1239,6 +661,9 @@ ofputil_protocol_set_base(enum ofputil_protocol cur, case OFPUTIL_P_NXM_TID: return ofputil_protocol_set_tid(OFPUTIL_P_NXM, tid); + case OFPUTIL_P_OF12: + return ofputil_protocol_set_tid(OFPUTIL_P_OF12, tid); + default: NOT_REACHED(); } @@ -1266,6 +691,9 @@ ofputil_protocol_to_string(enum ofputil_protocol protocol) case OFPUTIL_P_OF10_TID: return "OpenFlow10+table_id"; + + case OFPUTIL_P_OF12: + return NULL; } /* Check abbreviations. */ @@ -1441,7 +869,7 @@ ofputil_usable_protocols(const struct cls_rule *rule) { const struct flow_wildcards *wc = &rule->wc; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 14); /* NXM and OF1.1+ supports bitwise matching on ethernet addresses. */ if (!eth_mask_is_exact(wc->dl_src_mask) @@ -1459,7 +887,8 @@ ofputil_usable_protocols(const struct cls_rule *rule) } /* Only NXM supports matching ARP hardware addresses. */ - if (!(wc->wildcards & FWW_ARP_SHA) || !(wc->wildcards & FWW_ARP_THA)) { + if (!eth_addr_is_zero(wc->arp_sha_mask) || + !eth_addr_is_zero(wc->arp_tha_mask)) { return OFPUTIL_P_NXM_ANY; } @@ -1485,7 +914,7 @@ ofputil_usable_protocols(const struct cls_rule *rule) } /* Only NXM supports matching IPv6 flow label. */ - if (!(wc->wildcards & FWW_IPV6_LABEL)) { + if (wc->ipv6_label_mask) { return OFPUTIL_P_NXM_ANY; } @@ -1541,6 +970,9 @@ ofputil_encode_set_protocol(enum ofputil_protocol current, case OFPUTIL_P_OF10: return ofputil_encode_nx_set_flow_format(NXFF_OPENFLOW10); + case OFPUTIL_P_OF12: + return ofputil_encode_nx_set_flow_format(NXFF_OPENFLOW12); + case OFPUTIL_P_OF10_TID: case OFPUTIL_P_NXM_TID: NOT_REACHED(); @@ -1570,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; @@ -1588,6 +1021,9 @@ ofputil_nx_flow_format_to_protocol(enum nx_flow_format flow_format) case NXFF_NXM: return OFPUTIL_P_NXM; + case NXFF_OPENFLOW12: + return OFPUTIL_P_OF12; + default: return 0; } @@ -1610,6 +1046,8 @@ ofputil_nx_flow_format_to_string(enum nx_flow_format flow_format) return "openflow10"; case NXFF_NXM: return "nxm"; + case NXFF_OPENFLOW12: + return "openflow12"; default: NOT_REACHED(); } @@ -1621,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; @@ -1635,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; } @@ -1644,31 +1084,32 @@ ofputil_make_flow_mod_table_id(bool flow_mod_table_id) * flow_mod in 'fm'. Returns 0 if successful, otherwise an OpenFlow error * code. * - * Does not validate the flow_mod actions. */ + * Uses 'ofpacts' to store the abstract OFPACT_* version of 'oh''s actions. + * The caller must initialize 'ofpacts' and retains ownership of it. + * 'fm->ofpacts' will point into the 'ofpacts' buffer. + * + * Does not validate the flow_mod actions. The caller should do that, with + * ofpacts_check(). */ enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, const struct ofp_header *oh, - enum ofputil_protocol protocol) + 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; - /* Dissect the message. */ + /* Get the ofp_flow_mod. */ ofm = ofpbuf_pull(&b, sizeof *ofm); - error = ofputil_pull_actions(&b, b.size, &fm->actions, &fm->n_actions); - if (error) { - return error; - } /* Set priority based on original wildcards. Normally we'd allow * ofputil_cls_rule_from_match() to do this for us, but @@ -1683,6 +1124,12 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, ofputil_cls_rule_from_ofp10_match(&ofm->match, priority, &fm->cr); ofputil_normalize_rule(&fm->cr); + /* Now get the actions. */ + error = ofpacts_pull_openflow10(&b, b.size, ofpacts); + if (error) { + return error; + } + /* Translate the message. */ command = ntohs(ofm->command); fm->cookie = htonll(0); @@ -1693,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; @@ -1705,7 +1152,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, if (error) { return error; } - error = ofputil_pull_actions(&b, b.size, &fm->actions, &fm->n_actions); + error = ofpacts_pull_openflow10(&b, b.size, ofpacts); if (error) { return error; } @@ -1727,6 +1174,8 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, NOT_REACHED(); } + fm->ofpacts = ofpacts->data; + fm->ofpacts_len = ofpacts->size; if (protocol & OFPUTIL_P_TID) { fm->command = command & 0xff; fm->table_id = command >> 8; @@ -1744,7 +1193,6 @@ struct ofpbuf * ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, enum ofputil_protocol protocol) { - size_t actions_len = fm->n_actions * sizeof *fm->actions; struct ofp_flow_mod *ofm; struct nx_flow_mod *nfm; struct ofpbuf *msg; @@ -1758,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 + actions_len); - ofm = put_openflow(sizeof *ofm, OFPT10_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); @@ -1773,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 + actions_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); @@ -1790,12 +1239,15 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, nfm->match_len = htons(match_len); break; + case OFPUTIL_P_OF12: default: NOT_REACHED(); } - ofpbuf_put(msg, fm->actions, actions_len); - update_openflow_length(msg); + if (fm->ofpacts) { + ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg); + } + ofpmsg_update_length(msg); return msg; } @@ -1832,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); @@ -1849,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; } @@ -1882,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. */ @@ -1917,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); @@ -1936,20 +1381,23 @@ 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; break; } + case OFPUTIL_P_OF12: default: NOT_REACHED(); } @@ -1988,32 +1436,31 @@ ofputil_flow_stats_request_usable_protocols( * 'flow_age_extension' as true so that the contents of 'msg' determine the * 'idle_age' and 'hard_age' members in 'fs'. * + * Uses 'ofpacts' to store the abstract OFPACT_* version of the flow stats + * reply's actions. The caller must initialize 'ofpacts' and retains ownership + * of it. 'fs->ofpacts' will point into the 'ofpacts' buffer. + * * Returns 0 if successful, EOF if no replies were left in this 'msg', * otherwise a positive errno value. */ int ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, struct ofpbuf *msg, - bool flow_age_extension) + 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; @@ -2031,8 +1478,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, return EINVAL; } - if (ofputil_pull_actions(msg, length - sizeof *ofs, - &fs->actions, &fs->n_actions)) { + if (ofpacts_pull_openflow10(msg, length - sizeof *ofs, ofpacts)) { return EINVAL; } @@ -2048,9 +1494,9 @@ 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, length; + size_t match_len, actions_len, length; nfs = ofpbuf_try_pull(msg, sizeof *nfs); if (!nfs) { @@ -2071,9 +1517,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, return EINVAL; } - if (ofputil_pull_actions(msg, - length - sizeof *nfs - ROUND_UP(match_len, 8), - &fs->actions, &fs->n_actions)) { + actions_len = length - sizeof *nfs - ROUND_UP(match_len, 8); + if (ofpacts_pull_openflow10(msg, actions_len, ofpacts)) { return EINVAL; } @@ -2099,6 +1544,9 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, NOT_REACHED(); } + fs->ofpacts = ofpacts->data; + fs->ofpacts_len = ofpacts->size; + return 0; } @@ -2119,16 +1567,19 @@ void ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, struct list *replies) { - size_t act_len = fs->n_actions * sizeof *fs->actions; - const struct ofp_stats_msg *osm; + struct ofpbuf *reply = ofpbuf_from_list(list_back(replies)); + size_t start_ofs = reply->size; + enum ofpraw raw; - osm = ofpbuf_from_list(list_back(replies))->data; - if (osm->type == htons(OFPST_FLOW)) { - size_t len = offsetof(struct ofp_flow_stats, actions) + act_len; + ofpraw_decode_partial(&raw, reply->data, reply->size); + if (raw == OFPRAW_OFPST_FLOW_REPLY) { struct ofp_flow_stats *ofs; - ofs = ofputil_append_stats_reply(len, replies); - ofs->length = htons(len); + ofpbuf_put_uninit(reply, sizeof *ofs); + ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply); + + ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs); + ofs->length = htons(reply->size - start_ofs); ofs->table_id = fs->table_id; ofs->pad = 0; ofputil_cls_rule_to_ofp10_match(&fs->rule, &ofs->match); @@ -2143,17 +1594,16 @@ 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))); - memcpy(ofs->actions, fs->actions, act_len); - } else if (osm->type == htons(OFPST_VENDOR)) { + } else if (raw == OFPRAW_NXST_FLOW_REPLY) { struct nx_flow_stats *nfs; - struct ofpbuf *msg; - size_t start_len; + int match_len; - msg = ofputil_reserve_stats_reply( - sizeof *nfs + NXM_MAX_LEN + act_len, replies); - start_len = msg->size; + ofpbuf_put_uninit(reply, sizeof *nfs); + match_len = nx_put_match(reply, false, &fs->rule, 0, 0); + ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply); - nfs = ofpbuf_put_uninit(msg, sizeof *nfs); + nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs); + nfs->length = htons(reply->size - start_ofs); nfs->table_id = fs->table_id; nfs->pad = 0; nfs->duration_sec = htonl(fs->duration_sec); @@ -2167,50 +1617,66 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, nfs->hard_age = htons(fs->hard_age < 0 ? 0 : fs->hard_age < UINT16_MAX ? fs->hard_age + 1 : UINT16_MAX); - nfs->match_len = htons(nx_put_match(msg, false, &fs->rule, 0, 0)); + nfs->match_len = htons(match_len); nfs->cookie = fs->cookie; nfs->packet_count = htonll(fs->packet_count); nfs->byte_count = htonll(fs->byte_count); - ofpbuf_put(msg, fs->actions, act_len); - nfs->length = htons(msg->size - start_len); } else { NOT_REACHED(); } + + ofpmp_postappend(replies, start_ofs); } /* Converts abstract ofputil_aggregate_stats 'stats' into an OFPST_AGGREGATE or - * NXST_AGGREGATE reply according to 'protocol', and returns the message. */ + * NXST_AGGREGATE reply matching 'request', and returns the message. */ 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 ofp_aggregate_stats_reply *asr; + uint64_t packet_count; + uint64_t byte_count; struct ofpbuf *msg; + enum ofpraw raw; - if (request->type == htons(OFPST_AGGREGATE)) { - struct ofp_aggregate_stats_reply *asr; - - asr = ofputil_make_stats_reply(sizeof *asr, request, &msg); - 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)) { - struct nx_aggregate_stats_reply *nasr; - - nasr = ofputil_make_stats_reply(sizeof *nasr, request, &msg); - assert(nasr->nsm.subtype == htonl(NXST_AGGREGATE)); - nasr->packet_count = htonll(stats->packet_count); - nasr->byte_count = htonll(stats->byte_count); - nasr->flow_count = htonl(stats->flow_count); + ofpraw_decode(&raw, request); + if (raw == OFPRAW_OFPST_AGGREGATE_REQUEST) { + packet_count = unknown_to_zero(stats->packet_count); + byte_count = unknown_to_zero(stats->byte_count); } else { - NOT_REACHED(); + packet_count = stats->packet_count; + byte_count = stats->byte_count; } + msg = ofpraw_alloc_stats_reply(request, 0); + asr = ofpbuf_put_zeros(msg, sizeof *asr); + put_32aligned_be64(&asr->packet_count, htonll(packet_count)); + put_32aligned_be64(&asr->byte_count, htonll(byte_count)); + asr->flow_count = htonl(stats->flow_count); + return msg; } +enum ofperr +ofputil_decode_aggregate_stats_reply(struct ofputil_aggregate_stats *stats, + const struct ofp_header *reply) +{ + struct ofp_aggregate_stats_reply *asr; + struct ofpbuf msg; + + ofpbuf_use_const(&msg, reply, ntohs(reply->length)); + ofpraw_pull_assert(&msg); + + 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); + + 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. */ @@ -2218,15 +1684,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; @@ -2236,13 +1703,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); @@ -2281,8 +1745,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); @@ -2300,10 +1765,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; @@ -2316,6 +1783,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, break; } + case OFPUTIL_P_OF12: default: NOT_REACHED(); } @@ -2327,32 +1795,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); @@ -2402,13 +1868,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; @@ -2421,12 +1885,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); @@ -2441,17 +1899,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; @@ -2461,7 +1918,7 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, } else { NOT_REACHED(); } - update_openflow_length(packet); + ofpmsg_update_length(packet); return packet; } @@ -2501,13 +1958,29 @@ ofputil_packet_in_reason_from_string(const char *s, return false; } +/* Converts an OFPT_PACKET_OUT in 'opo' into an abstract ofputil_packet_out in + * 'po'. + * + * Uses 'ofpacts' to store the abstract OFPACT_* version of the packet out + * message's actions. The caller must initialize 'ofpacts' and retains + * ownership of it. 'po->ofpacts' will point into the 'ofpacts' buffer. + * + * 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 @@ -2517,14 +1990,12 @@ 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 = ofputil_pull_actions(&b, ntohs(opo->actions_len), - &po->actions, &po->n_actions); + error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts); if (error) { return error; } + po->ofpacts = ofpacts->data; + po->ofpacts_len = ofpacts->size; if (po->buffer_id == UINT32_MAX) { po->packet = b.data; @@ -2725,12 +2196,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); } } @@ -2817,29 +2288,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; } @@ -2851,12 +2326,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 @@ -2869,12 +2344,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; } @@ -2907,15 +2383,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); } @@ -2937,9 +2418,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 */ @@ -2947,12 +2428,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) { @@ -2960,9 +2446,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; } @@ -2976,13 +2460,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; } @@ -2994,26 +2482,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; @@ -3024,7 +2510,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; @@ -3044,7 +2530,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); @@ -3053,7 +2540,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); @@ -3065,399 +2553,305 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm, return b; } + +/* ofputil_flow_monitor_request */ -struct ofpbuf * -ofputil_encode_packet_out(const struct ofputil_packet_out *po) +/* Converts an NXST_FLOW_MONITOR request in 'msg' into an abstract + * ofputil_flow_monitor_request in 'rq'. + * + * Multiple NXST_FLOW_MONITOR requests can be packed into a single OpenFlow + * message. Calling this function multiple times for a single 'msg' iterates + * through the requests. The caller must initially leave 'msg''s layer + * pointers null and not modify them between calls. + * + * Returns 0 if successful, EOF if no requests were left in this 'msg', + * otherwise an OFPERR_* value. */ +int +ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *rq, + struct ofpbuf *msg) { - struct ofp_packet_out *opo; - size_t actions_len; - struct ofpbuf *msg; - size_t size; + struct nx_flow_monitor_request *nfmr; + uint16_t flags; - actions_len = po->n_actions * sizeof *po->actions; - size = sizeof *opo + actions_len; - if (po->buffer_id == UINT32_MAX) { - size += po->packet_len; + if (!msg->l2) { + msg->l2 = msg->data; + ofpraw_pull_assert(msg); } - msg = ofpbuf_new(size); - opo = put_openflow(sizeof *opo, OFPT10_PACKET_OUT, msg); - opo->buffer_id = htonl(po->buffer_id); - opo->in_port = htons(po->in_port); - opo->actions_len = htons(actions_len); - ofpbuf_put(msg, po->actions, actions_len); - if (po->buffer_id == UINT32_MAX) { - ofpbuf_put(msg, po->packet, po->packet_len); + if (!msg->size) { + return EOF; } - update_openflow_length(msg); - return msg; -} + nfmr = ofpbuf_try_pull(msg, sizeof *nfmr); + if (!nfmr) { + VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR request has %zu " + "leftover bytes at end", msg->size); + return OFPERR_OFPBRC_BAD_LEN; + } -/* 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); + flags = ntohs(nfmr->flags); + if (!(flags & (NXFMF_ADD | NXFMF_DELETE | NXFMF_MODIFY)) + || flags & ~(NXFMF_INITIAL | NXFMF_ADD | NXFMF_DELETE + | NXFMF_MODIFY | NXFMF_ACTIONS | NXFMF_OWN)) { + VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR has bad flags %#"PRIx16, + flags); + return OFPERR_NXBRC_FM_BAD_FLAGS; + } + + if (!is_all_zeros(nfmr->zeros, sizeof nfmr->zeros)) { + return OFPERR_NXBRC_MUST_BE_ZERO; + } + + rq->id = ntohl(nfmr->id); + rq->flags = flags; + rq->out_port = ntohs(nfmr->out_port); + rq->table_id = nfmr->table_id; + + return nx_pull_match(msg, ntohs(nfmr->match_len), OFP_DEFAULT_PRIORITY, + &rq->match, NULL, NULL); } -/* 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) +void +ofputil_append_flow_monitor_request( + const struct ofputil_flow_monitor_request *rq, struct ofpbuf *msg) { - return make_nxmsg_xid(openflow_len, subtype, alloc_xid(), bufferp); + struct nx_flow_monitor_request *nfmr; + size_t start_ofs; + int match_len; + + if (!msg->size) { + ofpraw_put(OFPRAW_NXST_FLOW_MONITOR_REQUEST, OFP10_VERSION, msg); + } + + start_ofs = msg->size; + ofpbuf_put_zeros(msg, sizeof *nfmr); + match_len = nx_put_match(msg, false, &rq->match, htonll(0), htonll(0)); + + nfmr = ofpbuf_at_assert(msg, start_ofs, sizeof *nfmr); + nfmr->id = htonl(rq->id); + nfmr->flags = htons(rq->flags); + nfmr->out_port = htons(rq->out_port); + nfmr->match_len = htons(match_len); + nfmr->table_id = rq->table_id; } -/* 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. +/* Converts an NXST_FLOW_MONITOR reply (also known as a flow update) in 'msg' + * into an abstract ofputil_flow_update in 'update'. The caller must have + * initialized update->match to point to space allocated for a cls_rule. * - * The caller is responsible for freeing '*bufferp' when it is no longer - * needed. + * Uses 'ofpacts' to store the abstract OFPACT_* version of the update's + * actions (except for NXFME_ABBREV, which never includes actions). The caller + * must initialize 'ofpacts' and retains ownership of it. 'update->ofpacts' + * will point into the 'ofpacts' buffer. * - * 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. + * Multiple flow updates can be packed into a single OpenFlow message. Calling + * this function multiple times for a single 'msg' iterates through the + * updates. The caller must initially leave 'msg''s layer pointers null and + * not modify them between calls. * - * Returns the header. */ -void * -make_openflow_xid(size_t openflow_len, uint8_t type, ovs_be32 xid, - struct ofpbuf **bufferp) + * Returns 0 if successful, EOF if no updates were left in this 'msg', + * otherwise an OFPERR_* value. */ +int +ofputil_decode_flow_update(struct ofputil_flow_update *update, + struct ofpbuf *msg, struct ofpbuf *ofpacts) { - *bufferp = ofpbuf_new(openflow_len); - return put_openflow_xid(openflow_len, type, xid, *bufferp); -} + struct nx_flow_update_header *nfuh; + unsigned int length; -/* 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); -} + if (!msg->l2) { + msg->l2 = msg->data; + ofpraw_pull_assert(msg); + } -/* 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); -} + if (!msg->size) { + return EOF; + } -/* 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; -} + if (msg->size < sizeof(struct nx_flow_update_header)) { + goto bad_len; + } -/* 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); -} + nfuh = msg->data; + update->event = ntohs(nfuh->event); + length = ntohs(nfuh->length); + if (length > msg->size || length % 8) { + goto bad_len; + } -/* 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; + if (update->event == NXFME_ABBREV) { + struct nx_flow_update_abbrev *nfua; - nxh = put_openflow_xid(openflow_len, OFPT_VENDOR, xid, buffer); - nxh->vendor = htonl(NX_VENDOR_ID); - nxh->subtype = htonl(subtype); - return nxh; -} + if (length != sizeof *nfua) { + goto bad_len; + } -/* 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); -} + nfua = ofpbuf_pull(msg, sizeof *nfua); + update->xid = nfua->xid; + return 0; + } else if (update->event == NXFME_ADDED + || update->event == NXFME_DELETED + || update->event == NXFME_MODIFIED) { + struct nx_flow_update_full *nfuf; + unsigned int actions_len; + unsigned int match_len; + enum ofperr error; -static void -put_stats__(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; + if (length < sizeof *nfuf) { + goto bad_len; + } - 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; + nfuf = ofpbuf_pull(msg, sizeof *nfuf); + match_len = ntohs(nfuf->match_len); + if (sizeof *nfuf + match_len > length) { + goto bad_len; + } - osm = put_openflow_xid(sizeof *osm, ofp_type, xid, msg); - osm->type = ofpst_type; - } -} + update->reason = ntohs(nfuf->reason); + update->idle_timeout = ntohs(nfuf->idle_timeout); + update->hard_timeout = ntohs(nfuf->hard_timeout); + update->table_id = nfuf->table_id; + update->cookie = nfuf->cookie; -/* 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; + error = nx_pull_match(msg, match_len, ntohs(nfuf->priority), + update->match, NULL, NULL); + if (error) { + return error; + } + + actions_len = length - sizeof *nfuf - ROUND_UP(match_len, 8); + error = ofpacts_pull_openflow10(msg, actions_len, ofpacts); + if (error) { + return error; + } - msg = *bufferp = ofpbuf_new(openflow_len); - put_stats__(alloc_xid(), OFPT10_STATS_REQUEST, - htons(ofpst_type), htonl(nxst_subtype), msg); - ofpbuf_padto(msg, openflow_len); + update->ofpacts = ofpacts->data; + update->ofpacts_len = ofpacts->size; + return 0; + } else { + VLOG_WARN_RL(&bad_ofmsg_rl, + "NXST_FLOW_MONITOR reply has bad event %"PRIu16, + ntohs(nfuh->event)); + return OFPERR_OFPET_BAD_REQUEST; + } - return msg->data; +bad_len: + VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR reply has %zu " + "leftover bytes at end", msg->size); + return OFPERR_OFPBRC_BAD_LEN; } -static void -put_stats_reply__(const struct ofp_stats_msg *request, struct ofpbuf *msg) +uint32_t +ofputil_decode_flow_monitor_cancel(const struct ofp_header *oh) { - assert(request->header.type == OFPT10_STATS_REQUEST || - request->header.type == OFPT10_STATS_REPLY); - put_stats__(request->header.xid, OFPT10_STATS_REPLY, request->type, - (request->type != htons(OFPST_VENDOR) - ? htonl(0) - : ((const struct nicira_stats_msg *) request)->subtype), - msg); + const struct nx_flow_monitor_cancel *cancel = ofpmsg_body(oh); + + return ntohl(cancel->id); } -/* 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 * +ofputil_encode_flow_monitor_cancel(uint32_t id) { + struct nx_flow_monitor_cancel *nfmc; struct ofpbuf *msg; - msg = *bufferp = ofpbuf_new(openflow_len); - put_stats_reply__(request, msg); - ofpbuf_padto(msg, openflow_len); - - return msg->data; + msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MONITOR_CANCEL, OFP10_VERSION, 0); + nfmc = ofpbuf_put_uninit(msg, sizeof *nfmc); + nfmc->id = htonl(id); + return msg; } -/* 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) +ofputil_start_flow_update(struct list *replies) { struct ofpbuf *msg; - msg = ofpbuf_new(1024); - put_stats_reply__(request, 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); } -/* 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) +void +ofputil_append_flow_update(const struct ofputil_flow_update *update, + struct list *replies) { - struct ofpbuf *msg = ofpbuf_from_list(list_back(replies)); - struct ofp_stats_msg *osm = msg->data; + struct nx_flow_update_header *nfuh; + struct ofpbuf *msg; + size_t start_ofs; + + msg = ofpbuf_from_list(list_back(replies)); + start_ofs = msg->size; + + if (update->event == NXFME_ABBREV) { + struct nx_flow_update_abbrev *nfua; - if (msg->size + len <= UINT16_MAX) { - ofpbuf_prealloc_tailroom(msg, len); + nfua = ofpbuf_put_zeros(msg, sizeof *nfua); + nfua->xid = update->xid; } else { - osm->flags |= htons(OFPSF_REPLY_MORE); + struct nx_flow_update_full *nfuf; + int match_len; + + ofpbuf_put_zeros(msg, sizeof *nfuf); + match_len = nx_put_match(msg, false, update->match, + htonll(0), htonll(0)); + ofpacts_put_openflow10(update->ofpacts, update->ofpacts_len, msg); - msg = ofpbuf_new(MAX(1024, sizeof(struct nicira_stats_msg) + len)); - put_stats_reply__(osm, msg); - list_push_back(replies, &msg->list_node); + nfuf = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuf); + nfuf->reason = htons(update->reason); + nfuf->priority = htons(update->match->priority); + nfuf->idle_timeout = htons(update->idle_timeout); + nfuf->hard_timeout = htons(update->hard_timeout); + nfuf->match_len = htons(match_len); + nfuf->table_id = update->table_id; + nfuf->cookie = update->cookie; } - 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); -} + nfuh = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuh); + nfuh->length = htons(msg->size - start_ofs); + nfuh->event = htons(update->event); -/* 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; + ofpmp_postappend(replies, start_ofs); } - -/* Returns the number of bytes past the ofp_stats_msg header in 'oh'. */ -size_t -ofputil_stats_body_len(const struct ofp_header *oh) + +struct ofpbuf * +ofputil_encode_packet_out(const struct ofputil_packet_out *po) { - assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY); - return ntohs(oh->length) - sizeof(struct ofp_stats_msg); -} + struct ofp_packet_out *opo; + size_t actions_ofs; + struct ofpbuf *msg; + size_t size; -/* 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; -} + size = po->ofpacts_len; + if (po->buffer_id == UINT32_MAX) { + size += po->packet_len; + } -/* 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); -} + 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); -struct ofpbuf * -make_flow_mod(uint16_t command, const struct cls_rule *rule, - size_t actions_len) -{ - struct ofp_flow_mod *ofm; - size_t size = sizeof *ofm + actions_len; - struct ofpbuf *out = ofpbuf_new(size); - ofm = ofpbuf_put_zeros(out, sizeof *ofm); - ofm->header.version = OFP10_VERSION; - ofm->header.type = OFPT10_FLOW_MOD; - ofm->header.length = htons(size); - ofm->cookie = 0; - ofm->priority = htons(MIN(rule->priority, UINT16_MAX)); - ofputil_cls_rule_to_ofp10_match(rule, &ofm->match); - ofm->command = htons(command); - return out; -} + opo = msg->l3; + opo->buffer_id = htonl(po->buffer_id); + opo->in_port = htons(po->in_port); + opo->actions_len = htons(msg->size - actions_ofs); -struct ofpbuf * -make_add_flow(const struct cls_rule *rule, uint32_t buffer_id, - uint16_t idle_timeout, size_t actions_len) -{ - struct ofpbuf *out = make_flow_mod(OFPFC_ADD, rule, actions_len); - struct ofp_flow_mod *ofm = out->data; - ofm->idle_timeout = htons(idle_timeout); - ofm->hard_timeout = htons(OFP_FLOW_PERMANENT); - ofm->buffer_id = htonl(buffer_id); - return out; -} + if (po->buffer_id == UINT32_MAX) { + ofpbuf_put(msg, po->packet, po->packet_len); + } -struct ofpbuf * -make_packet_in(uint32_t buffer_id, uint16_t in_port, uint8_t reason, - const struct ofpbuf *payload, int max_send_len) -{ - struct ofp_packet_in *opi; - struct ofpbuf *buf; - int send_len; - - send_len = MIN(max_send_len, payload->size); - buf = ofpbuf_new(sizeof *opi + send_len); - opi = put_openflow_xid(offsetof(struct ofp_packet_in, data), - OFPT_PACKET_IN, 0, buf); - opi->buffer_id = htonl(buffer_id); - opi->total_len = htons(payload->size); - opi->in_port = htons(in_port); - opi->reason = reason; - ofpbuf_put(buf, payload->data, send_len); - update_openflow_length(buf); - - return buf; -} + ofpmsg_update_length(msg); + return 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 @@ -3465,20 +2859,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 * @@ -3661,277 +3056,6 @@ size_t ofputil_count_phy_ports(uint8_t ofp_version, struct ofpbuf *b) return b->size / ofputil_get_phy_port_size(ofp_version); } -static enum ofperr -check_resubmit_table(const struct nx_action_resubmit *nar) -{ - if (nar->pad[0] || nar->pad[1] || nar->pad[2]) { - return OFPERR_OFPBAC_BAD_ARGUMENT; - } - return 0; -} - -static enum ofperr -check_output_reg(const struct nx_action_output_reg *naor, - const struct flow *flow) -{ - struct mf_subfield src; - size_t i; - - for (i = 0; i < sizeof naor->zero; i++) { - if (naor->zero[i]) { - return OFPERR_OFPBAC_BAD_ARGUMENT; - } - } - - nxm_decode(&src, naor->src, naor->ofs_nbits); - return mf_check_src(&src, flow); -} - -enum ofperr -validate_actions(const union ofp_action *actions, size_t n_actions, - const struct flow *flow, int max_ports) -{ - const union ofp_action *a; - size_t left; - - OFPUTIL_ACTION_FOR_EACH (a, left, actions, n_actions) { - enum ofperr error; - uint16_t port; - int code; - - code = ofputil_decode_action(a); - if (code < 0) { - error = -code; - VLOG_WARN_RL(&bad_ofmsg_rl, - "action decoding error at offset %td (%s)", - (a - actions) * sizeof *a, ofperr_get_name(error)); - - return error; - } - - error = 0; - switch ((enum ofputil_action_code) code) { - case OFPUTIL_OFPAT10_OUTPUT: - error = ofputil_check_output_port(ntohs(a->output.port), - max_ports); - break; - - case OFPUTIL_OFPAT10_SET_VLAN_VID: - if (a->vlan_vid.vlan_vid & ~htons(0xfff)) { - error = OFPERR_OFPBAC_BAD_ARGUMENT; - } - break; - - case OFPUTIL_OFPAT10_SET_VLAN_PCP: - if (a->vlan_pcp.vlan_pcp & ~7) { - error = OFPERR_OFPBAC_BAD_ARGUMENT; - } - break; - - case OFPUTIL_OFPAT10_ENQUEUE: - port = ntohs(((const struct ofp_action_enqueue *) a)->port); - if (port >= max_ports && port != OFPP_IN_PORT - && port != OFPP_LOCAL) { - error = OFPERR_OFPBAC_BAD_OUT_PORT; - } - break; - - case OFPUTIL_NXAST_REG_MOVE: - error = nxm_check_reg_move((const struct nx_action_reg_move *) a, - flow); - break; - - case OFPUTIL_NXAST_REG_LOAD: - error = nxm_check_reg_load((const struct nx_action_reg_load *) a, - flow); - break; - - case OFPUTIL_NXAST_MULTIPATH: - error = multipath_check((const struct nx_action_multipath *) a, - flow); - break; - - case OFPUTIL_NXAST_AUTOPATH: - error = autopath_check((const struct nx_action_autopath *) a, - flow); - break; - - case OFPUTIL_NXAST_BUNDLE: - case OFPUTIL_NXAST_BUNDLE_LOAD: - error = bundle_check((const struct nx_action_bundle *) a, - max_ports, flow); - break; - - case OFPUTIL_NXAST_OUTPUT_REG: - error = check_output_reg((const struct nx_action_output_reg *) a, - flow); - break; - - case OFPUTIL_NXAST_RESUBMIT_TABLE: - error = check_resubmit_table( - (const struct nx_action_resubmit *) a); - break; - - case OFPUTIL_NXAST_LEARN: - error = learn_check((const struct nx_action_learn *) a, flow); - break; - - case OFPUTIL_NXAST_CONTROLLER: - if (((const struct nx_action_controller *) a)->zero) { - error = OFPERR_NXBAC_MUST_BE_ZERO; - } - break; - - case OFPUTIL_OFPAT10_STRIP_VLAN: - case OFPUTIL_OFPAT10_SET_NW_SRC: - case OFPUTIL_OFPAT10_SET_NW_DST: - case OFPUTIL_OFPAT10_SET_NW_TOS: - case OFPUTIL_OFPAT10_SET_TP_SRC: - case OFPUTIL_OFPAT10_SET_TP_DST: - case OFPUTIL_OFPAT10_SET_DL_SRC: - case OFPUTIL_OFPAT10_SET_DL_DST: - case OFPUTIL_NXAST_RESUBMIT: - case OFPUTIL_NXAST_SET_TUNNEL: - case OFPUTIL_NXAST_SET_QUEUE: - case OFPUTIL_NXAST_POP_QUEUE: - case OFPUTIL_NXAST_NOTE: - case OFPUTIL_NXAST_SET_TUNNEL64: - case OFPUTIL_NXAST_EXIT: - case OFPUTIL_NXAST_DEC_TTL: - case OFPUTIL_NXAST_FIN_TIMEOUT: - break; - } - - if (error) { - VLOG_WARN_RL(&bad_ofmsg_rl, "bad action at offset %td (%s)", - (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 OFPERR_OFPBAC_BAD_LEN; - } - return 0; -} - -struct ofputil_action { - int code; - unsigned int min_len; - unsigned int max_len; -}; - -static const struct ofputil_action action_bad_type - = { -OFPERR_OFPBAC_BAD_TYPE, 0, UINT_MAX }; -static const struct ofputil_action action_bad_len - = { -OFPERR_OFPBAC_BAD_LEN, 0, UINT_MAX }; -static const struct ofputil_action action_bad_vendor - = { -OFPERR_OFPBAC_BAD_VENDOR, 0, UINT_MAX }; - -static const struct ofputil_action * -ofputil_decode_ofpat_action(const union ofp_action *a) -{ - enum ofp10_action_type type = ntohs(a->type); - - switch (type) { -#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \ - case ENUM: { \ - static const struct ofputil_action action = { \ - OFPUTIL_##ENUM, \ - sizeof(struct STRUCT), \ - sizeof(struct STRUCT) \ - }; \ - return &action; \ - } -#include "ofp-util.def" - - case OFPAT10_VENDOR: - default: - return &action_bad_type; - } -} - -static const struct ofputil_action * -ofputil_decode_nxast_action(const union ofp_action *a) -{ - const struct nx_action_header *nah = (const struct nx_action_header *) a; - enum nx_action_subtype subtype = ntohs(nah->subtype); - - switch (subtype) { -#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \ - case ENUM: { \ - static const struct ofputil_action action = { \ - OFPUTIL_##ENUM, \ - sizeof(struct STRUCT), \ - EXTENSIBLE ? UINT_MAX : sizeof(struct STRUCT) \ - }; \ - return &action; \ - } -#include "ofp-util.def" - - case NXAST_SNAT__OBSOLETE: - case NXAST_DROP_SPOOFED_ARP__OBSOLETE: - default: - return &action_bad_type; - } -} - -/* Parses 'a' to determine its type. Returns a nonnegative OFPUTIL_OFPAT10_* or - * 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 - * longer than the amount of space allocated to 'a'). - * - * This function verifies that 'a''s length is correct for the type of action - * that it represents. */ -int -ofputil_decode_action(const union ofp_action *a) -{ - const struct ofputil_action *action; - uint16_t len = ntohs(a->header.len); - - if (a->type != htons(OFPAT10_VENDOR)) { - action = ofputil_decode_ofpat_action(a); - } else { - switch (ntohl(a->vendor.vendor)) { - case NX_VENDOR_ID: - if (len < sizeof(struct nx_action_header)) { - return -OFPERR_OFPBAC_BAD_LEN; - } - action = ofputil_decode_nxast_action(a); - break; - default: - action = &action_bad_vendor; - break; - } - } - - return (len >= action->min_len && len <= action->max_len - ? action->code - : -OFPERR_OFPBAC_BAD_LEN); -} - -/* Parses 'a' and returns its type as an OFPUTIL_OFPAT10_* or OFPUTIL_NXAST_* - * constant. The caller must have already validated that 'a' is a valid action - * understood by Open vSwitch (e.g. by a previous successful call to - * ofputil_decode_action()). */ -enum ofputil_action_code -ofputil_decode_action_unsafe(const union ofp_action *a) -{ - const struct ofputil_action *action; - - if (a->type != htons(OFPAT10_VENDOR)) { - action = ofputil_decode_ofpat_action(a); - } else { - action = ofputil_decode_nxast_action(a); - } - - return action->code; -} - /* Returns the 'enum ofputil_action_code' corresponding to 'name' (e.g. if * 'name' is "output" then the return value is OFPUTIL_OFPAT10_OUTPUT), or -1 if * 'name' is not the name of any action. @@ -3941,7 +3065,9 @@ int ofputil_action_code_from_name(const char *name) { static const char *names[OFPUTIL_N_ACTIONS] = { -#define OFPAT10_ACTION(ENUM, STRUCT, NAME) NAME, + NULL, +#define OFPAT10_ACTION(ENUM, STRUCT, NAME) NAME, +#define OFPAT11_ACTION(ENUM, STRUCT, NAME) NAME, #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME, #include "ofp-util.def" }; @@ -3965,8 +3091,12 @@ void * ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf) { switch (code) { + case OFPUTIL_ACTION_INVALID: + NOT_REACHED(); + #define OFPAT10_ACTION(ENUM, STRUCT, NAME) \ case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf); +#define OFPAT11_ACTION OFPAT10_ACTION #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \ case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf); #include "ofp-util.def" @@ -3990,6 +3120,7 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf) ofputil_init_##ENUM(s); \ return s; \ } +#define OFPAT11_ACTION OFPAT10_ACTION #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \ void \ ofputil_init_##ENUM(struct STRUCT *s) \ @@ -4010,22 +3141,6 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf) } #include "ofp-util.def" -/* Returns true if 'action' outputs to 'port', false otherwise. */ -bool -action_outputs_to_port(const union ofp_action *action, ovs_be16 port) -{ - switch (ofputil_decode_action(action)) { - case OFPUTIL_OFPAT10_OUTPUT: - return action->output.port == port; - case OFPUTIL_OFPAT10_ENQUEUE: - return ((const struct ofp_action_enqueue *) action)->port == port; - case OFPUTIL_NXAST_CONTROLLER: - return port == htons(OFPP_CONTROLLER); - default: - return false; - } -} - /* "Normalizes" the wildcards in 'rule'. That means: * * 1. If the type of level N is known, then only the valid fields for that @@ -4101,14 +3216,14 @@ ofputil_normalize_rule(struct cls_rule *rule) wc.wildcards |= FWW_NW_TTL; } if (!(may_match & MAY_ARP_SHA)) { - wc.wildcards |= FWW_ARP_SHA; + memset(wc.arp_sha_mask, 0, ETH_ADDR_LEN); } if (!(may_match & MAY_ARP_THA)) { - wc.wildcards |= FWW_ARP_THA; + memset(wc.arp_tha_mask, 0, ETH_ADDR_LEN); } if (!(may_match & MAY_IPV6)) { wc.ipv6_src_mask = wc.ipv6_dst_mask = in6addr_any; - wc.wildcards |= FWW_IPV6_LABEL; + wc.ipv6_label_mask = htonl(0); } if (!(may_match & MAY_ND_TARGET)) { wc.nd_target_mask = in6addr_any; @@ -4133,57 +3248,6 @@ ofputil_normalize_rule(struct cls_rule *rule) } } -/* Attempts to pull 'actions_len' bytes from the front of 'b'. Returns 0 if - * successful, otherwise an OpenFlow error. - * - * If successful, the first action is stored in '*actionsp' and the number of - * "union ofp_action" size elements into '*n_actionsp'. Otherwise NULL and 0 - * are stored, respectively. - * - * This function does not check that the actions are valid (the caller should - * do so, with validate_actions()). The caller is also responsible for making - * sure that 'b->data' is initially aligned appropriately for "union - * ofp_action". */ -enum ofperr -ofputil_pull_actions(struct ofpbuf *b, unsigned int actions_len, - union ofp_action **actionsp, size_t *n_actionsp) -{ - if (actions_len % OFP_ACTION_ALIGN != 0) { - VLOG_WARN_RL(&bad_ofmsg_rl, "OpenFlow message actions length %u " - "is not a multiple of %d", actions_len, OFP_ACTION_ALIGN); - goto error; - } - - *actionsp = ofpbuf_try_pull(b, actions_len); - if (*actionsp == NULL) { - VLOG_WARN_RL(&bad_ofmsg_rl, "OpenFlow message actions length %u " - "exceeds remaining message length (%zu)", - actions_len, b->size); - goto error; - } - - *n_actionsp = actions_len / OFP_ACTION_ALIGN; - return 0; - -error: - *actionsp = NULL; - *n_actionsp = 0; - return OFPERR_OFPBRC_BAD_LEN; -} - -bool -ofputil_actions_equal(const union ofp_action *a, size_t n_a, - const union ofp_action *b, size_t n_b) -{ - return n_a == n_b && (!n_a || !memcmp(a, b, n_a * sizeof *a)); -} - -union ofp_action * -ofputil_actions_clone(const union ofp_action *actions, size_t n) -{ - return n ? xmemdup(actions, n * sizeof *actions) : NULL; -} - /* Parses a key or a key-value pair from '*stringp'. * * On success: Stores the key into '*keyp'. Stores the value, if present, into