X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fofp-util.c;h=23f7eda28f61853a8131b72df2a5c0ebed64fbf0;hb=0a2869d524fc3612b4b77a9df4991bff2aa3b465;hp=f1aefdd30cbeb46e51168ee71ee37e4ca45f9d80;hpb=e016fb630d66ba29c37fe4246f0acf80f11c1b3f;p=cascardo%2Fovs.git diff --git a/lib/ofp-util.c b/lib/ofp-util.c index f1aefdd30..23f7eda28 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -41,6 +41,7 @@ #include "ofpbuf.h" #include "openflow/netronome-ext.h" #include "packets.h" +#include "pktbuf.h" #include "random.h" #include "tun-metadata.h" #include "unaligned.h" @@ -63,56 +64,6 @@ static ovs_be32 ofputil_encode_table_config(enum ofputil_table_miss, enum ofputil_table_vacancy, enum ofp_version); -static enum ofperr -ofputil_check_mask(uint16_t type, uint32_t mask) -{ - switch (type) { - case OFPACPT_PACKET_IN_SLAVE: - case OFPACPT_PACKET_IN_MASTER: - if (mask > MAXIMUM_MASK_PACKET_IN) { - return OFPERR_OFPACFC_INVALID; - } - break; - - case OFPACPT_FLOW_REMOVED_SLAVE: - case OFPACPT_FLOW_REMOVED_MASTER: - if (mask > MAXIMUM_MASK_FLOW_REMOVED) { - return OFPERR_OFPACFC_INVALID; - } - break; - - case OFPACPT_PORT_STATUS_SLAVE: - case OFPACPT_PORT_STATUS_MASTER: - if (mask > MAXIMUM_MASK_PORT_STATUS) { - return OFPERR_OFPACFC_INVALID; - } - break; - - case OFPACPT_ROLE_STATUS_SLAVE: - case OFPACPT_ROLE_STATUS_MASTER: - if (mask > MAXIMUM_MASK_ROLE_STATUS) { - return OFPERR_OFPACFC_INVALID; - } - break; - - case OFPACPT_TABLE_STATUS_SLAVE: - case OFPACPT_TABLE_STATUS_MASTER: - if ((mask < MINIMUM_MASK_TABLE_STATUS && mask != 0) | - (mask > MAXIMUM_MASK_TABLE_STATUS)) { - return OFPERR_OFPACFC_INVALID; - } - break; - - case OFPACPT_REQUESTFORWARD_SLAVE: - case OFPACPT_REQUESTFORWARD_MASTER: - if (mask > MAXIMUM_MASK_REQUESTFORWARD) { - return OFPERR_OFPACFC_INVALID; - } - break; - } - return 0; -} - /* Given the wildcard bit count in the least-significant 6 of 'wcbits', returns * an IP netmask with a 1 in each bit that must match and a 0 in each bit that * is wildcarded. @@ -1293,13 +1244,12 @@ version_bitmap_from_version(uint8_t ofp_version) bool ofputil_decode_hello(const struct ofp_header *oh, uint32_t *allowed_versions) { - struct ofpbuf msg; - bool ok = true; - - ofpbuf_use_const(&msg, oh, ntohs(oh->length)); + struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length)); ofpbuf_pull(&msg, sizeof *oh); *allowed_versions = version_bitmap_from_version(oh->version); + + bool ok = true; while (msg.size) { const struct ofp_hello_elem_header *oheh; unsigned int len; @@ -1594,14 +1544,12 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, { ovs_be16 raw_flags; enum ofperr error; - struct ofpbuf b; - enum ofpraw raw; /* Ignored for non-delete actions */ fm->delete_reason = OFPRR_DELETE; - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); if (raw == OFPRAW_OFPT11_FLOW_MOD) { /* Standard OpenFlow 1.1+ flow_mod. */ const struct ofp11_flow_mod *ofm; @@ -1822,12 +1770,9 @@ ofputil_decode_meter_mod(const struct ofp_header *oh, struct ofputil_meter_mod *mm, struct ofpbuf *bands) { - const struct ofp13_meter_mod *omm; - struct ofpbuf b; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); ofpraw_pull_assert(&b); - omm = ofpbuf_pull(&b, sizeof *omm); + const struct ofp13_meter_mod *omm = ofpbuf_pull(&b, sizeof *omm); /* Translate the message. */ mm->command = ntohs(omm->command); @@ -2391,11 +2336,8 @@ ofputil_decode_queue_get_config_request(const struct ofp_header *oh, const struct ofp10_queue_get_config_request *qgcr10; const struct ofp11_queue_get_config_request *qgcr11; const struct ofp14_queue_desc_request *qdr14; - enum ofpraw raw; - struct ofpbuf b; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); switch ((int) raw) { case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST: @@ -2663,8 +2605,8 @@ ofputil_pull_queue_get_config_reply14(struct ofpbuf *msg, } len -= sizeof *oqd14; - struct ofpbuf properties; - ofpbuf_use_const(&properties, ofpbuf_pull(msg, len), len); + struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len), + len); while (properties.size > 0) { struct ofpbuf payload; uint64_t type; @@ -2744,11 +2686,8 @@ enum ofperr ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr, const struct ofp_header *oh) { - enum ofpraw raw; - struct ofpbuf b; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); switch ((int) raw) { case OFPRAW_OFPST10_FLOW_REQUEST: return ofputil_decode_ofpst10_flow_request(fsr, b.data, false); @@ -3176,13 +3115,10 @@ 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)); + struct ofpbuf msg = ofpbuf_const_initializer(reply, ntohs(reply->length)); ofpraw_pull_assert(&msg); - asr = msg.msg; + struct ofp_aggregate_stats_reply *asr = msg.msg; 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); @@ -3197,11 +3133,8 @@ enum ofperr ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, const struct ofp_header *oh) { - enum ofpraw raw; - struct ofpbuf b; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); if (raw == OFPRAW_OFPT11_FLOW_REMOVED) { const struct ofp12_flow_removed *ofr; enum ofperr error; @@ -3361,31 +3294,30 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, return msg; } +/* Decodes the packet-in message starting at 'oh' into '*pin'. Populates + * 'pin->packet' and 'pin->len' with the part of the packet actually included + * in the message, and '*total_len' with the original length of the packet + * (which is larger than 'packet->len' if only part of the packet was + * included). Stores the packet's buffer ID in '*buffer_id' (UINT32_MAX if it + * was not buffered). + * + * Returns 0 if successful, otherwise an OpenFlow error code. */ enum ofperr -ofputil_decode_packet_in(struct ofputil_packet_in *pin, - const struct ofp_header *oh) +ofputil_decode_packet_in(const struct ofp_header *oh, + struct ofputil_packet_in *pin, + size_t *total_len, uint32_t *buffer_id) { - enum ofpraw raw; - struct ofpbuf b; - memset(pin, 0, sizeof *pin); pin->cookie = OVS_BE64_MAX; - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); if (raw == OFPRAW_OFPT13_PACKET_IN || raw == OFPRAW_OFPT12_PACKET_IN) { - const struct ofp13_packet_in *opi; - int error; - size_t packet_in_size; - - if (raw == OFPRAW_OFPT12_PACKET_IN) { - packet_in_size = sizeof (struct ofp12_packet_in); - } else { - packet_in_size = sizeof (struct ofp13_packet_in); - } - - opi = ofpbuf_pull(&b, packet_in_size); - error = oxm_pull_match_loose(&b, &pin->flow_metadata); + const struct ofp12_packet_in *opi = ofpbuf_pull(&b, sizeof *opi); + const ovs_be64 *cookie = (raw == OFPRAW_OFPT13_PACKET_IN + ? ofpbuf_pull(&b, sizeof *cookie) + : NULL); + enum ofperr error = oxm_pull_match_loose(&b, &pin->flow_metadata); if (error) { return error; } @@ -3394,30 +3326,30 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, return OFPERR_OFPBRC_BAD_LEN; } - pin->reason = opi->pi.reason; - pin->table_id = opi->pi.table_id; - pin->buffer_id = ntohl(opi->pi.buffer_id); - pin->total_len = ntohs(opi->pi.total_len); - - if (raw == OFPRAW_OFPT13_PACKET_IN) { - pin->cookie = opi->cookie; + pin->reason = opi->reason; + pin->table_id = opi->table_id; + *buffer_id = ntohl(opi->buffer_id); + *total_len = ntohs(opi->total_len); + if (cookie) { + pin->cookie = *cookie; } pin->packet = b.data; - pin->packet_len = b.size; + pin->len = b.size; } else if (raw == OFPRAW_OFPT10_PACKET_IN) { const struct ofp10_packet_in *opi; opi = ofpbuf_pull(&b, offsetof(struct ofp10_packet_in, data)); pin->packet = opi->data; - pin->packet_len = b.size; + pin->len = b.size; match_init_catchall(&pin->flow_metadata); - match_set_in_port(&pin->flow_metadata, u16_to_ofp(ntohs(opi->in_port))); + match_set_in_port(&pin->flow_metadata, + u16_to_ofp(ntohs(opi->in_port))); pin->reason = opi->reason; - pin->buffer_id = ntohl(opi->buffer_id); - pin->total_len = ntohs(opi->total_len); + *buffer_id = ntohl(opi->buffer_id); + *total_len = ntohs(opi->total_len); } else if (raw == OFPRAW_OFPT11_PACKET_IN) { const struct ofp11_packet_in *opi; ofp_port_t in_port; @@ -3426,16 +3358,16 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, opi = ofpbuf_pull(&b, sizeof *opi); pin->packet = b.data; - pin->packet_len = b.size; + pin->len = b.size; - pin->buffer_id = ntohl(opi->buffer_id); + *buffer_id = ntohl(opi->buffer_id); error = ofputil_port_from_ofp11(opi->in_port, &in_port); if (error) { return error; } match_init_catchall(&pin->flow_metadata); match_set_in_port(&pin->flow_metadata, in_port); - pin->total_len = ntohs(opi->total_len); + *total_len = ntohs(opi->total_len); pin->reason = opi->reason; pin->table_id = opi->table_id; } else if (raw == OFPRAW_NXT_PACKET_IN) { @@ -3457,11 +3389,11 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, pin->table_id = npi->table_id; pin->cookie = npi->cookie; - pin->buffer_id = ntohl(npi->buffer_id); - pin->total_len = ntohs(npi->total_len); + *buffer_id = ntohl(npi->buffer_id); + *total_len = ntohs(npi->total_len); pin->packet = b.data; - pin->packet_len = b.size; + pin->len = b.size; } else { OVS_NOT_REACHED(); } @@ -3469,149 +3401,189 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, return 0; } +static int +encode_packet_in_reason(enum ofp_packet_in_reason reason, + enum ofp_version version) +{ + switch (reason) { + case OFPR_NO_MATCH: + case OFPR_ACTION: + case OFPR_INVALID_TTL: + return reason; + + case OFPR_ACTION_SET: + case OFPR_GROUP: + case OFPR_PACKET_OUT: + return version < OFP14_VERSION ? OFPR_ACTION : reason; + + case OFPR_EXPLICIT_MISS: + return version < OFP13_VERSION ? OFPR_ACTION : OFPR_NO_MATCH; + + case OFPR_IMPLICIT_MISS: + return OFPR_NO_MATCH; + + case OFPR_N_REASONS: + default: + OVS_NOT_REACHED(); + } +} + static struct ofpbuf * -ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin) +ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin, + uint32_t buffer_id) { struct ofp10_packet_in *opi; - struct ofpbuf *packet; + struct ofpbuf *msg; - packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION, - htonl(0), pin->packet_len); - opi = ofpbuf_put_zeros(packet, offsetof(struct ofp10_packet_in, data)); - opi->total_len = htons(pin->total_len); + msg = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION, + htonl(0), pin->len); + opi = ofpbuf_put_zeros(msg, offsetof(struct ofp10_packet_in, data)); + opi->total_len = htons(pin->len); opi->in_port = htons(ofp_to_u16(pin->flow_metadata.flow.in_port.ofp_port)); - opi->reason = pin->reason; - opi->buffer_id = htonl(pin->buffer_id); + opi->reason = encode_packet_in_reason(pin->reason, OFP10_VERSION); + opi->buffer_id = htonl(buffer_id); - ofpbuf_put(packet, pin->packet, pin->packet_len); - - return packet; + return msg; } static struct ofpbuf * -ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin) +ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin, + uint32_t buffer_id) { struct nx_packet_in *npi; - struct ofpbuf *packet; + struct ofpbuf *msg; size_t match_len; /* The final argument is just an estimate of the space required. */ - packet = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION, - htonl(0), NXM_TYPICAL_LEN + 2 + pin->packet_len); - ofpbuf_put_zeros(packet, sizeof *npi); - match_len = nx_put_match(packet, &pin->flow_metadata, 0, 0); - ofpbuf_put_zeros(packet, 2); - ofpbuf_put(packet, pin->packet, pin->packet_len); - - npi = packet->msg; - npi->buffer_id = htonl(pin->buffer_id); - npi->total_len = htons(pin->total_len); - npi->reason = pin->reason; + msg = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION, + htonl(0), NXM_TYPICAL_LEN + 2 + pin->len); + ofpbuf_put_zeros(msg, sizeof *npi); + match_len = nx_put_match(msg, &pin->flow_metadata, 0, 0); + ofpbuf_put_zeros(msg, 2); + + npi = msg->msg; + npi->buffer_id = htonl(buffer_id); + npi->total_len = htons(pin->len); + npi->reason = encode_packet_in_reason(pin->reason, OFP10_VERSION); npi->table_id = pin->table_id; npi->cookie = pin->cookie; npi->match_len = htons(match_len); - return packet; + return msg; } static struct ofpbuf * -ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin) +ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin, + uint32_t buffer_id) { struct ofp11_packet_in *opi; - struct ofpbuf *packet; + struct ofpbuf *msg; - packet = ofpraw_alloc_xid(OFPRAW_OFPT11_PACKET_IN, OFP11_VERSION, - htonl(0), pin->packet_len); - opi = ofpbuf_put_zeros(packet, sizeof *opi); - opi->buffer_id = htonl(pin->buffer_id); - opi->in_port = ofputil_port_to_ofp11(pin->flow_metadata.flow.in_port.ofp_port); + msg = ofpraw_alloc_xid(OFPRAW_OFPT11_PACKET_IN, OFP11_VERSION, + htonl(0), pin->len); + opi = ofpbuf_put_zeros(msg, sizeof *opi); + opi->buffer_id = htonl(buffer_id); + opi->in_port = ofputil_port_to_ofp11( + pin->flow_metadata.flow.in_port.ofp_port); opi->in_phy_port = opi->in_port; - opi->total_len = htons(pin->total_len); - opi->reason = pin->reason; + opi->total_len = htons(pin->len); + opi->reason = encode_packet_in_reason(pin->reason, OFP11_VERSION); opi->table_id = pin->table_id; - ofpbuf_put(packet, pin->packet, pin->packet_len); - - return packet; + return msg; } static struct ofpbuf * ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin, - enum ofputil_protocol protocol) -{ - struct ofp13_packet_in *opi; - enum ofpraw packet_in_raw; - enum ofp_version packet_in_version; - size_t packet_in_size; - struct ofpbuf *packet; - - if (protocol == OFPUTIL_P_OF12_OXM) { - packet_in_raw = OFPRAW_OFPT12_PACKET_IN; - packet_in_version = OFP12_VERSION; - packet_in_size = sizeof (struct ofp12_packet_in); - } else { - packet_in_raw = OFPRAW_OFPT13_PACKET_IN; - packet_in_version = ofputil_protocol_to_ofp_version(protocol); - packet_in_size = sizeof (struct ofp13_packet_in); - } + enum ofp_version version, + uint32_t buffer_id) +{ + enum ofpraw raw = (version >= OFP13_VERSION + ? OFPRAW_OFPT13_PACKET_IN + : OFPRAW_OFPT12_PACKET_IN); + struct ofpbuf *msg; /* The final argument is just an estimate of the space required. */ - packet = ofpraw_alloc_xid(packet_in_raw, packet_in_version, - htonl(0), NXM_TYPICAL_LEN + 2 + pin->packet_len); - ofpbuf_put_zeros(packet, packet_in_size); - oxm_put_match(packet, &pin->flow_metadata, - ofputil_protocol_to_ofp_version(protocol)); - ofpbuf_put_zeros(packet, 2); - ofpbuf_put(packet, pin->packet, pin->packet_len); + msg = ofpraw_alloc_xid(raw, version, + htonl(0), NXM_TYPICAL_LEN + 2 + pin->len); - opi = packet->msg; - opi->pi.buffer_id = htonl(pin->buffer_id); - opi->pi.total_len = htons(pin->total_len); - opi->pi.reason = pin->reason; - opi->pi.table_id = pin->table_id; - if (protocol != OFPUTIL_P_OF12_OXM) { - opi->cookie = pin->cookie; + struct ofp12_packet_in *opi = ofpbuf_put_zeros(msg, sizeof *opi); + opi->buffer_id = htonl(buffer_id); + opi->total_len = htons(pin->len); + opi->reason = encode_packet_in_reason(pin->reason, version); + opi->table_id = pin->table_id; + + if (version >= OFP13_VERSION) { + ovs_be64 cookie = pin->cookie; + ofpbuf_put(msg, &cookie, sizeof cookie); } - return packet; + oxm_put_match(msg, &pin->flow_metadata, version); + ofpbuf_put_zeros(msg, 2); + + return msg; } -/* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message - * in the format specified by 'packet_in_format'. */ +/* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message for + * 'protocol', using the packet-in format specified by 'packet_in_format'. + * + * If 'pkt_buf' is nonnull and 'max_len' allows the packet to be buffered, this + * function will attempt to obtain a buffer ID from 'pktbuf' and truncate the + * packet to 'max_len' bytes. Otherwise, or if 'pktbuf' doesn't have a free + * buffer, it will send the whole packet without buffering. */ struct ofpbuf * ofputil_encode_packet_in(const struct ofputil_packet_in *pin, enum ofputil_protocol protocol, - enum nx_packet_in_format packet_in_format) + enum nx_packet_in_format packet_in_format, + uint16_t max_len, struct pktbuf *pktbuf) { - struct ofpbuf *packet; + enum ofp_version version = ofputil_protocol_to_ofp_version(protocol); + /* Get buffer ID. */ + ofp_port_t in_port = pin->flow_metadata.flow.in_port.ofp_port; + uint32_t buffer_id = (max_len != OFPCML12_NO_BUFFER && pktbuf + ? pktbuf_save(pktbuf, pin->packet, + pin->len, in_port) + : UINT32_MAX); + + struct ofpbuf *msg; switch (protocol) { case OFPUTIL_P_OF10_STD: case OFPUTIL_P_OF10_STD_TID: case OFPUTIL_P_OF10_NXM: case OFPUTIL_P_OF10_NXM_TID: - packet = (packet_in_format == NXPIF_NXM - ? ofputil_encode_nx_packet_in(pin) - : ofputil_encode_ofp10_packet_in(pin)); + msg = (packet_in_format == NXPIF_NXM + ? ofputil_encode_nx_packet_in(pin, buffer_id) + : ofputil_encode_ofp10_packet_in(pin, buffer_id)); break; case OFPUTIL_P_OF11_STD: - packet = ofputil_encode_ofp11_packet_in(pin); + msg = ofputil_encode_ofp11_packet_in(pin, buffer_id); break; case OFPUTIL_P_OF12_OXM: case OFPUTIL_P_OF13_OXM: case OFPUTIL_P_OF14_OXM: case OFPUTIL_P_OF15_OXM: - packet = ofputil_encode_ofp12_packet_in(pin, protocol); + msg = ofputil_encode_ofp12_packet_in(pin, version, buffer_id); break; default: OVS_NOT_REACHED(); } - ofpmsg_update_length(packet); - return packet; + /* Append some of the packet: + * + * - If not buffered, the whole thing. + * + * - Otherwise, no more than 'max_len' bytes. */ + ofpbuf_put(msg, pin->packet, + (buffer_id == UINT32_MAX + ? pin->len + : MIN(max_len, pin->len))); + + ofpmsg_update_length(msg); + return msg; } /* Returns a string form of 'reason'. The return value is either a statically @@ -3634,6 +3606,9 @@ ofputil_packet_in_reason_to_string(enum ofp_packet_in_reason reason, return "group"; case OFPR_PACKET_OUT: return "packet_out"; + case OFPR_EXPLICIT_MISS: + case OFPR_IMPLICIT_MISS: + return ""; case OFPR_N_REASONS: default: @@ -3675,11 +3650,8 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po, const struct ofp_header *oh, struct ofpbuf *ofpacts) { - enum ofpraw raw; - struct ofpbuf b; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); ofpbuf_clear(ofpacts); if (raw == OFPRAW_OFPT11_PACKET_OUT) { @@ -3868,24 +3840,18 @@ parse_ofp14_port_ethernet_property(const struct ofpbuf *payload, static enum ofperr ofputil_pull_ofp14_port(struct ofputil_phy_port *pp, struct ofpbuf *msg) { - struct ofpbuf properties; - struct ofp14_port *op; - enum ofperr error; - size_t len; - - op = ofpbuf_try_pull(msg, sizeof *op); + struct ofp14_port *op = ofpbuf_try_pull(msg, sizeof *op); if (!op) { return OFPERR_OFPBRC_BAD_LEN; } - len = ntohs(op->length); + size_t len = ntohs(op->length); if (len < sizeof *op || len - sizeof *op > msg->size) { return OFPERR_OFPBRC_BAD_LEN; } len -= sizeof *op; - ofpbuf_use_const(&properties, ofpbuf_pull(msg, len), len); - error = ofputil_port_from_ofp11(op->port_no, &pp->port_no); + enum ofperr error = ofputil_port_from_ofp11(op->port_no, &pp->port_no); if (error) { return error; } @@ -3895,6 +3861,8 @@ ofputil_pull_ofp14_port(struct ofputil_phy_port *pp, struct ofpbuf *msg) pp->config = ntohl(op->config) & OFPPC11_ALL; pp->state = ntohl(op->state) & OFPPS11_ALL; + struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len), + len); while (properties.size > 0) { struct ofpbuf payload; enum ofperr error; @@ -4023,11 +3991,9 @@ enum ofperr ofputil_decode_port_desc_stats_request(const struct ofp_header *request, ofp_port_t *port) { - struct ofpbuf b; - enum ofpraw raw; - - ofpbuf_use_const(&b, request, ntohs(request->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(request, + ntohs(request->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); if (raw == OFPRAW_OFPST10_PORT_DESC_REQUEST) { *port = OFPP_ANY; return 0; @@ -4091,13 +4057,10 @@ static bool ofputil_decode_switch_config(const struct ofp_header *oh, struct ofputil_switch_config *config) { - const struct ofp_switch_config *osc; - struct ofpbuf b; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); ofpraw_pull_assert(&b); - osc = ofpbuf_pull(&b, sizeof *osc); + const struct ofp_switch_config *osc = ofpbuf_pull(&b, sizeof *osc); config->frag = ntohs(osc->flags) & OFPC_FRAG_MASK; config->miss_send_len = ntohs(osc->miss_send_len); @@ -4190,23 +4153,18 @@ ofputil_capabilities_mask(enum ofp_version ofp_version) } } -/* Decodes an OpenFlow 1.0 or 1.1 "switch_features" structure 'osf' into an - * abstract representation in '*features'. Initializes '*b' to iterate over - * the OpenFlow port structures following 'osf' with later calls to - * ofputil_pull_phy_port(). Returns 0 if successful, otherwise an - * OFPERR_* value. */ +/* Pulls an OpenFlow "switch_features" structure from 'b' and decodes it into + * an abstract representation in '*features', readying 'b' to iterate over the + * OpenFlow port structures following 'osf' with later calls to + * ofputil_pull_phy_port(). Returns 0 if successful, otherwise an OFPERR_* + * value. */ enum ofperr -ofputil_decode_switch_features(const struct ofp_header *oh, - struct ofputil_switch_features *features, - struct ofpbuf *b) +ofputil_pull_switch_features(struct ofpbuf *b, + struct ofputil_switch_features *features) { - 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); + const struct ofp_header *oh = b->data; + enum ofpraw raw = ofpraw_pull_assert(b); + const struct ofp_switch_features *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; @@ -4371,14 +4329,10 @@ enum ofperr 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)); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); ofpraw_pull_assert(&b); - ops = ofpbuf_pull(&b, sizeof *ops); + const struct ofp_port_status *ops = ofpbuf_pull(&b, sizeof *ops); if (ops->reason != OFPPR_ADD && ops->reason != OFPPR_DELETE && ops->reason != OFPPR_MODIFY) { @@ -4386,7 +4340,7 @@ ofputil_decode_port_status(const struct ofp_header *oh, } ps->reason = ops->reason; - retval = ofputil_pull_phy_port(oh->version, &b, &ps->desc); + int retval = ofputil_pull_phy_port(oh->version, &b, &ps->desc); ovs_assert(retval != EOF); return retval; } @@ -4454,12 +4408,8 @@ enum ofperr ofputil_decode_port_mod(const struct ofp_header *oh, struct ofputil_port_mod *pm, bool loose) { - enum ofpraw raw; - struct ofpbuf b; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); - + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); if (raw == OFPRAW_OFPT10_PORT_MOD) { const struct ofp10_port_mod *opm = b.data; @@ -4730,33 +4680,26 @@ int ofputil_decode_table_features(struct ofpbuf *msg, struct ofputil_table_features *tf, bool loose) { - const struct ofp_header *oh; - struct ofp13_table_features *otf; - struct ofpbuf properties; - unsigned int len; - memset(tf, 0, sizeof *tf); if (!msg->header) { ofpraw_pull_assert(msg); } - oh = msg->header; if (!msg->size) { return EOF; } + const struct ofp_header *oh = msg->header; + struct ofp13_table_features *otf = msg->data; if (msg->size < sizeof *otf) { return OFPERR_OFPBPC_BAD_LEN; } - otf = msg->data; - len = ntohs(otf->length); + unsigned int len = ntohs(otf->length); if (len < sizeof *otf || len % 8 || len > msg->size) { return OFPERR_OFPBPC_BAD_LEN; } - ofpbuf_use_const(&properties, ofpbuf_pull(msg, len), len); - ofpbuf_pull(&properties, sizeof *otf); tf->table_id = otf->table_id; if (tf->table_id == OFPTT_ALL) { @@ -4777,6 +4720,9 @@ ofputil_decode_table_features(struct ofpbuf *msg, } tf->max_entries = ntohl(otf->max_entries); + struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len), + len); + ofpbuf_pull(&properties, sizeof *otf); while (properties.size > 0) { struct ofpbuf payload; enum ofperr error; @@ -5021,10 +4967,6 @@ ofputil_decode_table_desc(struct ofpbuf *msg, struct ofputil_table_desc *td, enum ofp_version version) { - struct ofp14_table_desc *otd; - struct ofpbuf properties; - size_t length; - memset(td, 0, sizeof *td); if (!msg->header) { @@ -5035,7 +4977,7 @@ ofputil_decode_table_desc(struct ofpbuf *msg, return EOF; } - otd = ofpbuf_try_pull(msg, sizeof *otd); + struct ofp14_table_desc *otd = ofpbuf_try_pull(msg, sizeof *otd); if (!otd) { VLOG_WARN_RL(&bad_ofmsg_rl, "OFP14_TABLE_DESC reply has %"PRIu32" " "leftover bytes at end", msg->size); @@ -5043,19 +4985,20 @@ ofputil_decode_table_desc(struct ofpbuf *msg, } td->table_id = otd->table_id; - length = ntohs(otd->length); + size_t length = ntohs(otd->length); if (length < sizeof *otd || length - sizeof *otd > msg->size) { VLOG_WARN_RL(&bad_ofmsg_rl, "OFP14_TABLE_DESC reply claims invalid " "length %"PRIuSIZE, length); return OFPERR_OFPBRC_BAD_LEN; } length -= sizeof *otd; - ofpbuf_use_const(&properties, ofpbuf_pull(msg, length), length); td->eviction = ofputil_decode_table_eviction(otd->config, version); td->vacancy = ofputil_decode_table_vacancy(otd->config, version); td->eviction_flags = UINT32_MAX; + struct ofpbuf properties = ofpbuf_const_initializer( + ofpbuf_pull(msg, length), length); while (properties.size > 0) { struct ofpbuf payload; enum ofperr error; @@ -5299,17 +5242,14 @@ enum ofperr ofputil_decode_table_mod(const struct ofp_header *oh, struct ofputil_table_mod *pm) { - enum ofpraw raw; - struct ofpbuf b; - memset(pm, 0, sizeof *pm); pm->miss = OFPUTIL_TABLE_MISS_DEFAULT; pm->eviction = OFPUTIL_TABLE_EVICTION_DEFAULT; pm->eviction_flags = UINT32_MAX; pm->vacancy = OFPUTIL_TABLE_VACANCY_DEFAULT; - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); if (raw == OFPRAW_OFPT11_TABLE_MOD) { const struct ofp11_table_mod *otm = b.data; @@ -5423,12 +5363,8 @@ enum ofperr ofputil_decode_role_message(const struct ofp_header *oh, struct ofputil_role_request *rr) { - struct ofpbuf b; - enum ofpraw raw; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); - + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); if (raw == OFPRAW_OFPT12_ROLE_REQUEST || raw == OFPRAW_OFPT12_ROLE_REPLY) { const struct ofp12_role_request *orr = b.msg; @@ -5542,15 +5478,11 @@ enum ofperr ofputil_decode_role_status(const struct ofp_header *oh, struct ofputil_role_status *rs) { - struct ofpbuf b; - enum ofpraw raw; - const struct ofp14_role_status *r; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); ovs_assert(raw == OFPRAW_OFPT14_ROLE_STATUS); - r = b.msg; + const struct ofp14_role_status *r = b.msg; if (r->role != htonl(OFPCR12_ROLE_NOCHANGE) && r->role != htonl(OFPCR12_ROLE_EQUAL) && r->role != htonl(OFPCR12_ROLE_MASTER) && @@ -5609,10 +5541,7 @@ enum ofperr ofputil_decode_requestforward(const struct ofp_header *outer, struct ofputil_requestforward *rf) { - struct ofpbuf b; - enum ofperr error; - - ofpbuf_use_const(&b, outer, ntohs(outer->length)); + struct ofpbuf b = ofpbuf_const_initializer(outer, ntohs(outer->length)); /* Skip past outer message. */ enum ofpraw outer_raw = ofpraw_pull_assert(&b); @@ -5633,7 +5562,7 @@ ofputil_decode_requestforward(const struct ofp_header *outer, /* Parse inner message. */ enum ofptype type; - error = ofptype_decode(&type, inner); + enum ofperr error = ofptype_decode(&type, inner); if (error) { return error; } @@ -6443,13 +6372,11 @@ make_echo_request(enum ofp_version ofp_version) struct ofpbuf * make_echo_reply(const struct ofp_header *rq) { - struct ofpbuf rq_buf; - struct ofpbuf *reply; - - ofpbuf_use_const(&rq_buf, rq, ntohs(rq->length)); + struct ofpbuf rq_buf = ofpbuf_const_initializer(rq, ntohs(rq->length)); ofpraw_pull_assert(&rq_buf); - reply = ofpraw_alloc_reply(OFPRAW_OFPT_ECHO_REPLY, rq, rq_buf.size); + struct ofpbuf *reply = ofpraw_alloc_reply(OFPRAW_OFPT_ECHO_REPLY, + rq, rq_buf.size); ofpbuf_put(reply, rq_buf.data, rq_buf.size); return reply; } @@ -7198,24 +7125,18 @@ static enum ofperr ofputil_pull_ofp14_port_stats(struct ofputil_port_stats *ops, struct ofpbuf *msg) { - const struct ofp14_port_stats *ps14; - struct ofpbuf properties; - enum ofperr error; - size_t len; - - ps14 = ofpbuf_try_pull(msg, sizeof *ps14); + const struct ofp14_port_stats *ps14 = ofpbuf_try_pull(msg, sizeof *ps14); if (!ps14) { return OFPERR_OFPBRC_BAD_LEN; } - len = ntohs(ps14->length); + size_t len = ntohs(ps14->length); if (len < sizeof *ps14 || len - sizeof *ps14 > msg->size) { return OFPERR_OFPBRC_BAD_LEN; } len -= sizeof *ps14; - ofpbuf_use_const(&properties, ofpbuf_pull(msg, len), len); - error = ofputil_port_from_ofp11(ps14->port_no, &ops->port_no); + enum ofperr error = ofputil_port_from_ofp11(ps14->port_no, &ops->port_no); if (error) { return error; } @@ -7235,6 +7156,8 @@ ofputil_pull_ofp14_port_stats(struct ofputil_port_stats *ops, ops->stats.rx_crc_errors = UINT64_MAX; ops->stats.collisions = UINT64_MAX; + struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len), + len); while (properties.size > 0) { struct ofpbuf payload; enum ofperr error; @@ -7268,16 +7191,15 @@ ofputil_pull_ofp14_port_stats(struct ofputil_port_stats *ops, size_t ofputil_count_port_stats(const struct ofp_header *oh) { - struct ofputil_port_stats ps; - struct ofpbuf b; - size_t n = 0; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); ofpraw_pull_assert(&b); - while (!ofputil_decode_port_stats(&ps, &b)) { - n++; + + for (size_t n = 0; ; n++) { + struct ofputil_port_stats ps; + if (ofputil_decode_port_stats(&ps, &b)) { + return n; + } } - return n; } /* Converts an OFPST_PORT_STATS reply in 'msg' into an abstract @@ -7527,11 +7449,8 @@ ofputil_uninit_group_desc(struct ofputil_group_desc *gd) uint32_t ofputil_decode_group_desc_request(const struct ofp_header *oh) { - struct ofpbuf request; - enum ofpraw raw; - - ofpbuf_use_const(&request, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&request); + struct ofpbuf request = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&request); if (raw == OFPRAW_OFPST11_GROUP_DESC_REQUEST) { return OFPG_ALL; } else if (raw == OFPRAW_OFPST15_GROUP_DESC_REQUEST) { @@ -8061,7 +7980,6 @@ ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length, struct ofputil_bucket *bucket = NULL; struct ofpbuf ofpacts; enum ofperr err = OFPERR_OFPGMFC_BAD_BUCKET; - struct ofpbuf properties; size_t ob_len, actions_len, properties_len; ovs_be32 watch_port = ofputil_port_to_ofp11(OFPP_ANY); ovs_be32 watch_group = htonl(OFPG_ANY); @@ -8104,9 +8022,8 @@ ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length, } properties_len = ob_len - sizeof *ob - actions_len; - ofpbuf_use_const(&properties, ofpbuf_pull(msg, properties_len), - properties_len); - + struct ofpbuf properties = ofpbuf_const_initializer( + ofpbuf_pull(msg, properties_len), properties_len); while (properties.size > 0) { struct ofpbuf payload; uint64_t type; @@ -8278,11 +8195,8 @@ parse_ofp15_group_properties(struct ofpbuf *msg, struct ofputil_group_props *gp, size_t properties_len) { - struct ofpbuf properties; - - ofpbuf_use_const(&properties, ofpbuf_pull(msg, properties_len), - properties_len); - + struct ofpbuf properties = ofpbuf_const_initializer( + ofpbuf_pull(msg, properties_len), properties_len); while (properties.size > 0) { struct ofpbuf payload; enum ofperr error; @@ -8701,16 +8615,13 @@ enum ofperr ofputil_decode_group_mod(const struct ofp_header *oh, struct ofputil_group_mod *gm) { - enum ofp_version ofp_version = oh->version; - struct ofpbuf msg; - struct ofputil_bucket *bucket; - enum ofperr err; + ofputil_init_group_properties(&gm->props); - ofpbuf_use_const(&msg, oh, ntohs(oh->length)); + enum ofp_version ofp_version = oh->version; + struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length)); ofpraw_pull_assert(&msg); - ofputil_init_group_properties(&gm->props); - + enum ofperr err; switch (ofp_version) { case OFP11_VERSION: @@ -8728,7 +8639,6 @@ ofputil_decode_group_mod(const struct ofp_header *oh, default: OVS_NOT_REACHED(); } - if (err) { return err; } @@ -8762,6 +8672,7 @@ ofputil_decode_group_mod(const struct ofp_header *oh, return OFPERR_OFPGMFC_BAD_COMMAND; } + struct ofputil_bucket *bucket; LIST_FOR_EACH (bucket, list_node, &gm->buckets) { if (bucket->weight && gm->type != OFPGT11_SELECT) { return OFPERR_OFPGMFC_INVALID_GROUP; @@ -8868,16 +8779,15 @@ ofputil_encode_queue_stats_request(enum ofp_version ofp_version, size_t ofputil_count_queue_stats(const struct ofp_header *oh) { - struct ofputil_queue_stats qs; - struct ofpbuf b; - size_t n = 0; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); ofpraw_pull_assert(&b); - while (!ofputil_decode_queue_stats(&qs, &b)) { - n++; + + for (size_t n = 0; ; n++) { + struct ofputil_queue_stats qs; + if (ofputil_decode_queue_stats(&qs, &b)) { + return n; + } } - return n; } static enum ofperr @@ -9098,15 +9008,11 @@ enum ofperr ofputil_decode_bundle_ctrl(const struct ofp_header *oh, struct ofputil_bundle_ctrl_msg *msg) { - struct ofpbuf b; - enum ofpraw raw; - const struct ofp14_bundle_ctrl_msg *m; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); ovs_assert(raw == OFPRAW_OFPT14_BUNDLE_CONTROL); - m = b.msg; + const struct ofp14_bundle_ctrl_msg *m = b.msg; msg->bundle_id = ntohl(m->bundle_id); msg->type = ntohs(m->type); msg->flags = ntohs(m->flags); @@ -9256,20 +9162,13 @@ ofputil_is_bundlable(enum ofptype type) enum ofperr ofputil_decode_bundle_add(const struct ofp_header *oh, struct ofputil_bundle_add_msg *msg, - enum ofptype *type_ptr) + enum ofptype *typep) { - const struct ofp14_bundle_ctrl_msg *m; - struct ofpbuf b; - enum ofpraw raw; - size_t inner_len; - enum ofperr error; - enum ofptype type; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); ovs_assert(raw == OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE); - m = ofpbuf_pull(&b, sizeof *m); + const struct ofp14_bundle_ctrl_msg *m = ofpbuf_pull(&b, sizeof *m); msg->bundle_id = ntohl(m->bundle_id); msg->flags = ntohs(m->flags); @@ -9277,7 +9176,7 @@ ofputil_decode_bundle_add(const struct ofp_header *oh, if (msg->msg->version != oh->version) { return OFPERR_NXBFC_BAD_VERSION; } - inner_len = ntohs(msg->msg->length); + size_t inner_len = ntohs(msg->msg->length); if (inner_len < sizeof(struct ofp_header) || inner_len > b.size) { return OFPERR_OFPBFC_MSG_BAD_LEN; } @@ -9286,21 +9185,22 @@ ofputil_decode_bundle_add(const struct ofp_header *oh, } /* Reject unbundlable messages. */ - if (!type_ptr) { - type_ptr = &type; - } - error = ofptype_decode(type_ptr, msg->msg); + enum ofptype type; + enum ofperr error = ofptype_decode(&type, msg->msg); if (error) { VLOG_WARN_RL(&bad_ofmsg_rl, "OFPT14_BUNDLE_ADD_MESSAGE contained " "message is unparsable (%s)", ofperr_get_name(error)); return OFPERR_OFPBFC_MSG_UNSUP; /* 'error' would be confusing. */ } - if (!ofputil_is_bundlable(*type_ptr)) { + if (!ofputil_is_bundlable(type)) { VLOG_WARN_RL(&bad_ofmsg_rl, "%s message not allowed inside " - "OFPT14_BUNDLE_ADD_MESSAGE", ofptype_get_name(*type_ptr)); + "OFPT14_BUNDLE_ADD_MESSAGE", ofptype_get_name(type)); return OFPERR_OFPBFC_MSG_UNSUP; } + if (typep) { + *typep = type; + } return 0; } @@ -9398,13 +9298,10 @@ enum ofperr ofputil_decode_tlv_table_mod(const struct ofp_header *oh, struct ofputil_tlv_table_mod *ttm) { - struct ofpbuf msg; - struct nx_tlv_table_mod *nx_ttm; - - ofpbuf_use_const(&msg, oh, ntohs(oh->length)); + struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length)); ofpraw_pull_assert(&msg); - nx_ttm = ofpbuf_pull(&msg, sizeof *nx_ttm); + struct nx_tlv_table_mod *nx_ttm = ofpbuf_pull(&msg, sizeof *nx_ttm); ttm->command = ntohs(nx_ttm->command); if (ttm->command > NXTTMC_CLEAR) { VLOG_WARN_RL(&bad_ofmsg_rl, @@ -9444,13 +9341,10 @@ enum ofperr ofputil_decode_tlv_table_reply(const struct ofp_header *oh, struct ofputil_tlv_table_reply *ttr) { - struct ofpbuf msg; - struct nx_tlv_table_reply *nx_ttr; - - ofpbuf_use_const(&msg, oh, ntohs(oh->length)); + struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length)); ofpraw_pull_assert(&msg); - nx_ttr = ofpbuf_pull(&msg, sizeof *nx_ttr); + struct nx_tlv_table_reply *nx_ttr = ofpbuf_pull(&msg, sizeof *nx_ttr); ttr->max_option_space = ntohl(nx_ttr->max_option_space); ttr->max_fields = ntohs(nx_ttr->max_fields); @@ -9467,8 +9361,174 @@ ofputil_uninit_tlv_table(struct ovs_list *mappings) } } +const char * +ofputil_async_msg_type_to_string(enum ofputil_async_msg_type type) +{ + switch (type) { + case OAM_PACKET_IN: return "PACKET_IN"; + case OAM_PORT_STATUS: return "PORT_STATUS"; + case OAM_FLOW_REMOVED: return "FLOW_REMOVED"; + case OAM_ROLE_STATUS: return "ROLE_STATUS"; + case OAM_TABLE_STATUS: return "TABLE_STATUS"; + case OAM_REQUESTFORWARD: return "REQUESTFORWARD"; + + case OAM_N_TYPES: + default: + OVS_NOT_REACHED(); + } +} + +struct ofp14_async_prop { + uint64_t prop_type; + enum ofputil_async_msg_type oam; + bool master; + uint32_t allowed10, allowed14; +}; + +#define AP_PAIR(SLAVE_PROP_TYPE, OAM, A10, A14) \ + { SLAVE_PROP_TYPE, OAM, false, A10, (A14) ? (A14) : (A10) }, \ + { (SLAVE_PROP_TYPE + 1), OAM, true, A10, (A14) ? (A14) : (A10) } + +static const struct ofp14_async_prop async_props[] = { + AP_PAIR( 0, OAM_PACKET_IN, OFPR10_BITS, OFPR14_BITS), + AP_PAIR( 2, OAM_PORT_STATUS, (1 << OFPPR_N_REASONS) - 1, 0), + AP_PAIR( 4, OAM_FLOW_REMOVED, (1 << OVS_OFPRR_NONE) - 1, 0), + AP_PAIR( 6, OAM_ROLE_STATUS, (1 << OFPCRR_N_REASONS) - 1, 0), + AP_PAIR( 8, OAM_TABLE_STATUS, OFPTR_BITS, 0), + AP_PAIR(10, OAM_REQUESTFORWARD, (1 << OFPRFR_N_REASONS) - 1, 0), +}; + +#define FOR_EACH_ASYNC_PROP(VAR) \ + for (const struct ofp14_async_prop *VAR = async_props; \ + VAR < &async_props[ARRAY_SIZE(async_props)]; VAR++) + +static const struct ofp14_async_prop * +get_ofp14_async_config_prop_by_prop_type(uint64_t prop_type) +{ + FOR_EACH_ASYNC_PROP (ap) { + if (prop_type == ap->prop_type) { + return ap; + } + } + return NULL; +} + +static const struct ofp14_async_prop * +get_ofp14_async_config_prop_by_oam(enum ofputil_async_msg_type oam, + bool master) +{ + FOR_EACH_ASYNC_PROP (ap) { + if (ap->oam == oam && ap->master == master) { + return ap; + } + } + return NULL; +} + +static uint32_t +ofp14_async_prop_allowed(const struct ofp14_async_prop *prop, + enum ofp_version version) +{ + return version >= OFP14_VERSION ? prop->allowed14 : prop->allowed10; +} + +static ovs_be32 +encode_async_mask(const struct ofputil_async_cfg *src, + const struct ofp14_async_prop *ap, + enum ofp_version version) +{ + uint32_t mask = ap->master ? src->master[ap->oam] : src->slave[ap->oam]; + return htonl(mask & ofp14_async_prop_allowed(ap, version)); +} + +static enum ofperr +decode_async_mask(ovs_be32 src, + const struct ofp14_async_prop *ap, enum ofp_version version, + bool loose, struct ofputil_async_cfg *dst) +{ + uint32_t mask = ntohl(src); + uint32_t allowed = ofp14_async_prop_allowed(ap, version); + if (mask & ~allowed) { + OFPPROP_LOG(&bad_ofmsg_rl, loose, + "bad value %#x for %s (allowed mask %#x)", + mask, ofputil_async_msg_type_to_string(ap->oam), + allowed); + mask &= allowed; + if (!loose) { + return OFPERR_OFPACFC_INVALID; + } + } + + if (ap->oam == OAM_PACKET_IN) { + if (mask & (1u << OFPR_NO_MATCH)) { + mask |= 1u << OFPR_EXPLICIT_MISS; + if (version < OFP13_VERSION) { + mask |= 1u << OFPR_IMPLICIT_MISS; + } + } + } + + uint32_t *array = ap->master ? dst->master : dst->slave; + array[ap->oam] = mask; + return 0; +} + +static enum ofperr +parse_async_tlv(const struct ofpbuf *property, + const struct ofp14_async_prop *ap, + struct ofputil_async_cfg *ac, + enum ofp_version version, bool loose) +{ + enum ofperr error; + ovs_be32 mask; + + error = ofpprop_parse_be32(property, &mask); + if (error) { + return error; + } + + if (ofpprop_is_experimenter(ap->prop_type)) { + /* For experimenter properties, whether a property is for the master or + * slave role is indicated by both 'type' and 'exp_type' in struct + * ofp_prop_experimenter. Check that these are consistent. */ + const struct ofp_prop_experimenter *ope = property->data; + bool should_be_master = ope->type == htons(0xffff); + if (should_be_master != ap->master) { + VLOG_WARN_RL(&bad_ofmsg_rl, "async property type %#"PRIx16" " + "indicates %s role but exp_type %"PRIu32" indicates " + "%s role", + ntohs(ope->type), + should_be_master ? "master" : "slave", + ntohl(ope->exp_type), + ap->master ? "master" : "slave"); + return OFPERR_OFPBPC_BAD_EXP_TYPE; + } + } + + return decode_async_mask(mask, ap, version, loose, ac); +} + +static void +decode_legacy_async_masks(const ovs_be32 masks[2], + enum ofputil_async_msg_type oam, + enum ofp_version version, + struct ofputil_async_cfg *dst) +{ + for (int i = 0; i < 2; i++) { + bool master = i == 0; + const struct ofp14_async_prop *ap + = get_ofp14_async_config_prop_by_oam(oam, master); + decode_async_mask(masks[i], ap, version, true, dst); + } +} + /* Decodes the OpenFlow "set async config" request and "get async config - * reply" message in '*oh' into an abstract form in 'master' and 'slave'. + * reply" message in '*oh' into an abstract form in 'ac'. + * + * Some versions of the "set async config" request change only some of the + * settings and leave the others alone. This function uses 'basis' as the + * initial state for decoding these. Other versions of the request change all + * the settings; this function ignores 'basis' when decoding these. * * If 'loose' is true, this function ignores properties and values that it does * not understand, as a controller would want to do when interpreting @@ -9484,107 +9544,50 @@ ofputil_uninit_tlv_table(struct ovs_list *mappings) * Returns error code OFPERR_OFPACFC_UNSUPPORTED if the configuration is not * supported.*/ enum ofperr -ofputil_decode_set_async_config(const struct ofp_header *oh, - uint32_t master[OAM_N_TYPES], - uint32_t slave[OAM_N_TYPES], - bool loose) +ofputil_decode_set_async_config(const struct ofp_header *oh, bool loose, + const struct ofputil_async_cfg *basis, + struct ofputil_async_cfg *ac) { - enum ofpraw raw; - struct ofpbuf b; - - ofpbuf_use_const(&b, oh, ntohs(oh->length)); - raw = ofpraw_pull_assert(&b); + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); if (raw == OFPRAW_OFPT13_SET_ASYNC || raw == OFPRAW_NXT_SET_ASYNC_CONFIG || raw == OFPRAW_OFPT13_GET_ASYNC_REPLY) { const struct nx_async_config *msg = ofpmsg_body(oh); - master[OAM_PACKET_IN] = ntohl(msg->packet_in_mask[0]); - master[OAM_PORT_STATUS] = ntohl(msg->port_status_mask[0]); - master[OAM_FLOW_REMOVED] = ntohl(msg->flow_removed_mask[0]); - - slave[OAM_PACKET_IN] = ntohl(msg->packet_in_mask[1]); - slave[OAM_PORT_STATUS] = ntohl(msg->port_status_mask[1]); - slave[OAM_FLOW_REMOVED] = ntohl(msg->flow_removed_mask[1]); - + *ac = OFPUTIL_ASYNC_CFG_INIT; + decode_legacy_async_masks(msg->packet_in_mask, OAM_PACKET_IN, + oh->version, ac); + decode_legacy_async_masks(msg->port_status_mask, OAM_PORT_STATUS, + oh->version, ac); + decode_legacy_async_masks(msg->flow_removed_mask, OAM_FLOW_REMOVED, + oh->version, ac); } else if (raw == OFPRAW_OFPT14_SET_ASYNC || - raw == OFPRAW_OFPT14_GET_ASYNC_REPLY) { - + raw == OFPRAW_OFPT14_GET_ASYNC_REPLY || + raw == OFPRAW_NXT_SET_ASYNC_CONFIG2) { + *ac = *basis; while (b.size > 0) { struct ofpbuf property; enum ofperr error; uint64_t type; - uint32_t mask; error = ofpprop_pull__(&b, &property, 8, 0xfffe, &type); if (error) { return error; } - error = ofpprop_parse_u32(&property, &mask); + const struct ofp14_async_prop *ap + = get_ofp14_async_config_prop_by_prop_type(type); + error = (ap + ? parse_async_tlv(&property, ap, ac, oh->version, loose) + : OFPPROP_UNKNOWN(loose, "async config", type)); if (error) { - return error; - } - - if (!loose) { - error = ofputil_check_mask(type, mask); - if (error) { - return error; + /* Most messages use OFPBPC_BAD_TYPE but async has its own (who + * knows why, it's OpenFlow. */ + if (error == OFPERR_OFPBPC_BAD_TYPE) { + error = OFPERR_OFPACFC_UNSUPPORTED; } - } - - switch (type) { - case OFPACPT_PACKET_IN_SLAVE: - slave[OAM_PACKET_IN] = mask; - break; - - case OFPACPT_PACKET_IN_MASTER: - master[OAM_PACKET_IN] = mask; - break; - - case OFPACPT_PORT_STATUS_SLAVE: - slave[OAM_PORT_STATUS] = mask; - break; - - case OFPACPT_PORT_STATUS_MASTER: - master[OAM_PORT_STATUS] = mask; - break; - - case OFPACPT_FLOW_REMOVED_SLAVE: - slave[OAM_FLOW_REMOVED] = mask; - break; - - case OFPACPT_FLOW_REMOVED_MASTER: - master[OAM_FLOW_REMOVED] = mask; - break; - - case OFPACPT_ROLE_STATUS_SLAVE: - slave[OAM_ROLE_STATUS] = mask; - break; - - case OFPACPT_ROLE_STATUS_MASTER: - master[OAM_ROLE_STATUS] = mask; - break; - - case OFPACPT_TABLE_STATUS_SLAVE: - slave[OAM_TABLE_STATUS] = mask; - break; - - case OFPACPT_TABLE_STATUS_MASTER: - master[OAM_TABLE_STATUS] = mask; - break; - - case OFPACPT_REQUESTFORWARD_SLAVE: - slave[OAM_REQUESTFORWARD] = mask; - break; - - case OFPACPT_REQUESTFORWARD_MASTER: - master[OAM_REQUESTFORWARD] = mask; - break; - - default: - error = loose ? 0 : OFPERR_OFPACFC_UNSUPPORTED; return error; } } @@ -9594,88 +9597,118 @@ ofputil_decode_set_async_config(const struct ofp_header *oh, return 0; } -/* Append all asynchronous configuration properties in GET_ASYNC_REPLY - * message, describing if various set of asynchronous messages are enabled - * or not. */ -static enum ofperr -ofputil_get_async_reply(struct ofpbuf *buf, const uint32_t master_mask, - const uint32_t slave_mask, const uint32_t type) +static void +encode_legacy_async_masks(const struct ofputil_async_cfg *ac, + enum ofputil_async_msg_type oam, + enum ofp_version version, + ovs_be32 masks[2]) { - int role; - - for (role = 0; role < 2; role++) { - enum ofp14_async_config_prop_type prop_type; - - switch (type) { - case OAM_PACKET_IN: - prop_type = (role ? OFPACPT_PACKET_IN_SLAVE - : OFPACPT_PACKET_IN_MASTER); - break; - - case OAM_PORT_STATUS: - prop_type = (role ? OFPACPT_PORT_STATUS_SLAVE - : OFPACPT_PORT_STATUS_MASTER); - break; - - case OAM_FLOW_REMOVED: - prop_type = (role ? OFPACPT_FLOW_REMOVED_SLAVE - : OFPACPT_FLOW_REMOVED_MASTER); - break; - - case OAM_ROLE_STATUS: - prop_type = (role ? OFPACPT_ROLE_STATUS_SLAVE - : OFPACPT_ROLE_STATUS_MASTER); - break; - - case OAM_TABLE_STATUS: - prop_type = (role ? OFPACPT_TABLE_STATUS_SLAVE - : OFPACPT_TABLE_STATUS_MASTER); - break; - - case OAM_REQUESTFORWARD: - prop_type = (role ? OFPACPT_REQUESTFORWARD_SLAVE - : OFPACPT_REQUESTFORWARD_MASTER); - break; + for (int i = 0; i < 2; i++) { + bool master = i == 0; + const struct ofp14_async_prop *ap + = get_ofp14_async_config_prop_by_oam(oam, master); + masks[i] = encode_async_mask(ac, ap, version); + } +} - default: - return OFPERR_OFPBRC_BAD_TYPE; +static void +ofputil_put_async_config__(const struct ofputil_async_cfg *ac, + struct ofpbuf *buf, bool tlv, + enum ofp_version version, uint32_t oams) +{ + if (!tlv) { + struct nx_async_config *msg = ofpbuf_put_zeros(buf, sizeof *msg); + encode_legacy_async_masks(ac, OAM_PACKET_IN, version, + msg->packet_in_mask); + encode_legacy_async_masks(ac, OAM_PORT_STATUS, version, + msg->port_status_mask); + encode_legacy_async_masks(ac, OAM_FLOW_REMOVED, version, + msg->flow_removed_mask); + } else { + FOR_EACH_ASYNC_PROP (ap) { + if (oams & (1u << ap->oam)) { + size_t ofs = buf->size; + ofpprop_put_be32(buf, ap->prop_type, + encode_async_mask(ac, ap, version)); + + /* For experimenter properties, we need to use type 0xfffe for + * master and 0xffff for slaves. */ + if (ofpprop_is_experimenter(ap->prop_type)) { + struct ofp_prop_experimenter *ope + = ofpbuf_at_assert(buf, ofs, sizeof *ope); + ope->type = ap->master ? htons(0xffff) : htons(0xfffe); + } + } } - ofpprop_put_u32(buf, prop_type, role ? slave_mask : master_mask); } - - return 0; } -/* Returns a OpenFlow message that encodes 'asynchronous configuration' properly - * as a reply to get async config request. */ +/* Encodes and returns a reply to the OFPT_GET_ASYNC_REQUEST in 'oh' that + * states that the asynchronous message configuration is 'ac'. */ struct ofpbuf * -ofputil_encode_get_async_config(const struct ofp_header *oh, - uint32_t master[OAM_N_TYPES], - uint32_t slave[OAM_N_TYPES]) +ofputil_encode_get_async_reply(const struct ofp_header *oh, + const struct ofputil_async_cfg *ac) { struct ofpbuf *buf; - uint32_t type; - buf = ofpraw_alloc_reply((oh->version < OFP14_VERSION - ? OFPRAW_OFPT13_GET_ASYNC_REPLY - : OFPRAW_OFPT14_GET_ASYNC_REPLY), oh, 0); + enum ofpraw raw = (oh->version < OFP14_VERSION + ? OFPRAW_OFPT13_GET_ASYNC_REPLY + : OFPRAW_OFPT14_GET_ASYNC_REPLY); + struct ofpbuf *reply = ofpraw_alloc_reply(raw, oh, 0); + ofputil_put_async_config__(ac, reply, + raw == OFPRAW_OFPT14_GET_ASYNC_REPLY, + oh->version, UINT32_MAX); + return reply; - if (oh->version < OFP14_VERSION) { - struct nx_async_config *msg; - msg = ofpbuf_put_zeros(buf, sizeof *msg); + return buf; +} - msg->packet_in_mask[0] = htonl(master[OAM_PACKET_IN]); - msg->port_status_mask[0] = htonl(master[OAM_PORT_STATUS]); - msg->flow_removed_mask[0] = htonl(master[OAM_FLOW_REMOVED]); +/* Encodes and returns a message, in a format appropriate for OpenFlow version + * 'ofp_version', that sets the asynchronous message configuration to 'ac'. + * + * Specify 'oams' as a bitmap of OAM_* that indicate the asynchronous messages + * to configure. OF1.0 through OF1.3 can't natively configure a subset of + * messages, so more messages than requested may be configured. OF1.0 through + * OF1.3 also can't configure OVS extension OAM_* values, so if 'oam' includes + * any extensions then this function encodes an Open vSwitch extension message + * that does support configuring OVS extension OAM_*. */ +struct ofpbuf * +ofputil_encode_set_async_config(const struct ofputil_async_cfg *ac, + uint32_t oams, enum ofp_version ofp_version) +{ + enum ofpraw raw = (ofp_version >= OFP14_VERSION ? OFPRAW_OFPT14_SET_ASYNC + : oams & OAM_EXTENSIONS ? OFPRAW_NXT_SET_ASYNC_CONFIG2 + : ofp_version >= OFP13_VERSION ? OFPRAW_OFPT13_SET_ASYNC + : OFPRAW_NXT_SET_ASYNC_CONFIG); + struct ofpbuf *request = ofpraw_alloc(raw, ofp_version, 0); + ofputil_put_async_config__(ac, request, + (raw == OFPRAW_OFPT14_SET_ASYNC || + raw == OFPRAW_NXT_SET_ASYNC_CONFIG2), + ofp_version, oams); + return request; +} - msg->packet_in_mask[1] = htonl(slave[OAM_PACKET_IN]); - msg->port_status_mask[1] = htonl(slave[OAM_PORT_STATUS]); - msg->flow_removed_mask[1] = htonl(slave[OAM_FLOW_REMOVED]); - } else if (oh->version == OFP14_VERSION) { - for (type = 0; type < OAM_N_TYPES; type++) { - ofputil_get_async_reply(buf, master[type], slave[type], type); - } +struct ofputil_async_cfg +ofputil_async_cfg_default(enum ofp_version version) +{ + /* We enable all of the OF1.4 reasons regardless of 'version' because the + * reasons added in OF1.4 just are just refinements of the OFPR_ACTION + * introduced in OF1.0, breaking it into more specific categories. When we + * encode these for earlier OpenFlow versions, we translate them into + * OFPR_ACTION. */ + uint32_t pin = OFPR14_BITS & ~(1u << OFPR_INVALID_TTL); + pin |= 1u << OFPR_EXPLICIT_MISS; + if (version <= OFP12_VERSION) { + pin |= 1u << OFPR_IMPLICIT_MISS; } - return buf; + return (struct ofputil_async_cfg) { + .master[OAM_PACKET_IN] = pin, + + .master[OAM_FLOW_REMOVED] + = (version >= OFP14_VERSION ? OFPRR14_BITS : OFPRR10_BITS), + + .master[OAM_PORT_STATUS] = OFPPR_BITS, + .slave[OAM_PORT_STATUS] = OFPPR_BITS, + }; }