/* Decodes information about a queue from the OFPT_QUEUE_GET_CONFIG_REPLY in * 'reply' and stores it in '*queue'. ofputil_decode_queue_get_config_reply() * must already have pulled off the main header. * * This function returns EOF if the last queue has already been decoded, 0 if a * queue was successfully decoded into '*queue', or an ofperr if there was a * problem decoding 'reply'. */ int ofputil_pull_queue_get_config_reply(struct ofpbuf *msg, struct ofputil_queue_config *queue) { enum ofpraw raw; if (!msg->header) { /* Pull OpenFlow header. */ raw = ofpraw_pull_assert(msg); /* Pull protocol-specific ofp_queue_get_config_reply header (OF1.4 * doesn't have one at all). */ if (raw == OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY) { ofpbuf_pull(msg, sizeof(struct ofp10_queue_get_config_reply)); } else if (raw == OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY) { ofpbuf_pull(msg, sizeof(struct ofp11_queue_get_config_reply)); } else { ovs_assert(raw == OFPRAW_OFPST14_QUEUE_DESC_REPLY); } } else { raw = ofpraw_decode_assert(msg->header); } queue->min_rate = UINT16_MAX; queue->max_rate = UINT16_MAX; if (!msg->size) { return EOF; } else if (raw == OFPRAW_OFPST14_QUEUE_DESC_REPLY) { return ofputil_pull_queue_get_config_reply14(msg, queue); } else { return ofputil_pull_queue_get_config_reply10(msg, queue); } }
/* Decodes the NXT_FLOW_MOD_TABLE_ID message at 'oh'. Returns the message's * argument, that is, whether the flow_mod_table_id feature should be * enabled. */ bool ofputil_decode_nx_flow_mod_table_id(const struct ofp_header *oh) { struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); ovs_assert(ofpraw_pull_assert(&b) == OFPRAW_NXT_FLOW_MOD_TABLE_ID); uint8_t *enable = ofpbuf_pull(&b, 8); return *enable != 0; }
enum ofperr ofputil_decode_bundle_add(const struct ofp_header *oh, struct ofputil_bundle_add_msg *msg, enum ofptype *typep) { struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); /* Pull the outer ofp_header. */ enum ofpraw raw = ofpraw_pull_assert(&b); ovs_assert(raw == OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE || raw == OFPRAW_ONFT13_BUNDLE_ADD_MESSAGE); /* Pull the bundle_ctrl header. */ const struct ofp14_bundle_ctrl_msg *m = ofpbuf_pull(&b, sizeof *m); msg->bundle_id = ntohl(m->bundle_id); msg->flags = ntohs(m->flags); /* Pull the inner ofp_header. */ if (b.size < sizeof(struct ofp_header)) { return OFPERR_OFPBFC_MSG_BAD_LEN; } msg->msg = b.data; if (msg->msg->version != oh->version) { return OFPERR_OFPBFC_BAD_VERSION; } 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; } if (msg->msg->xid != oh->xid) { return OFPERR_OFPBFC_MSG_BAD_XID; } /* Reject unbundlable messages. */ enum ofptype type; enum ofperr error = ofptype_decode(&type, msg->msg); if (error) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&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)) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "%s message not allowed inside " "OFPT14_BUNDLE_ADD_MESSAGE", ofptype_get_name(type)); return OFPERR_OFPBFC_MSG_UNSUP; } if (typep) { *typep = type; } return 0; }
/* Returns the number of queue stats elements in OFPTYPE_QUEUE_STATS_REPLY * message 'oh'. */ size_t ofputil_count_queue_stats(const struct ofp_header *oh) { struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); ofpraw_pull_assert(&b); for (size_t n = 0; ; n++) { struct ofputil_queue_stats qs; if (ofputil_decode_queue_stats(&qs, &b)) { return n; } } }
enum ofperr ofputil_decode_bundle_ctrl(const struct ofp_header *oh, struct ofputil_bundle_ctrl_msg *msg) { struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); enum ofpraw raw = ofpraw_pull_assert(&b); ovs_assert(raw == OFPRAW_OFPT14_BUNDLE_CONTROL || raw == OFPRAW_ONFT13_BUNDLE_CONTROL); 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); return 0; }
/* Returns the protocol specified in the NXT_SET_FLOW_FORMAT message at 'oh' * (either OFPUTIL_P_OF10_STD or OFPUTIL_P_OF10_NXM) or 0 if the message is * invalid. */ enum ofputil_protocol ofputil_decode_nx_set_flow_format(const struct ofp_header *oh) { struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); ovs_assert(ofpraw_pull_assert(&b) == OFPRAW_NXT_SET_FLOW_FORMAT); ovs_be32 *flow_formatp = ofpbuf_pull(&b, sizeof *flow_formatp); uint32_t flow_format = ntohl(*flow_formatp); switch (flow_format) { case NXFF_OPENFLOW10: return OFPUTIL_P_OF10_STD; case NXFF_NXM: return OFPUTIL_P_OF10_NXM; default: VLOG_WARN_RL(&rl, "NXT_SET_FLOW_FORMAT message specified invalid " "flow format %"PRIu32, flow_format); return 0; } }
/* Decodes 'oh', which must be an OFPT_GET_CONFIG_REPLY or OFPT_SET_CONFIG * message, into 'config'. Returns false if 'oh' contained any flags that * aren't specified in its version of OpenFlow, true otherwise. */ static bool ofputil_decode_switch_config(const struct ofp_header *oh, struct ofputil_switch_config *config) { struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); ofpraw_pull_assert(&b); 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); ovs_be16 valid_mask = htons(OFPC_FRAG_MASK); if (oh->version < OFP13_VERSION) { const ovs_be16 ttl_bit = htons(OFPC_INVALID_TTL_TO_CONTROLLER); valid_mask |= ttl_bit; config->invalid_ttl_to_controller = (osc->flags & ttl_bit) != 0; } else { config->invalid_ttl_to_controller = -1; } return !(osc->flags & ~valid_mask); }
/* Parses OFPT_QUEUE_GET_CONFIG request 'oh', storing the port specified by the * request into '*port'. Returns 0 if successful, otherwise an OpenFlow error * code. */ enum ofperr ofputil_decode_queue_get_config_request(const struct ofp_header *oh, ofp_port_t *port, uint32_t *queue) { const struct ofp10_queue_get_config_request *qgcr10; const struct ofp11_queue_get_config_request *qgcr11; const struct ofp14_queue_desc_request *qdr14; 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: qgcr10 = b.data; *port = u16_to_ofp(ntohs(qgcr10->port)); *queue = OFPQ_ALL; break; case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST: qgcr11 = b.data; *queue = OFPQ_ALL; enum ofperr error = ofputil_port_from_ofp11(qgcr11->port, port); if (error || *port == OFPP_ANY) { return error; } break; case OFPRAW_OFPST14_QUEUE_DESC_REQUEST: qdr14 = b.data; *queue = ntohl(qdr14->queue); return ofputil_port_from_ofp11(qdr14->port, port); default: OVS_NOT_REACHED(); } return (ofp_to_u16(*port) < ofp_to_u16(OFPP_MAX) ? 0 : OFPERR_OFPQOFC_BAD_PORT); }
/* 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_pull_switch_features(struct ofpbuf *b, struct ofputil_switch_features *features) { 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; features->auxiliary_id = 0; features->capabilities = ntohl(osf->capabilities) & ofputil_capabilities_mask(oh->version); if (raw == OFPRAW_OFPT10_FEATURES_REPLY) { if (osf->capabilities & htonl(OFPC10_STP)) { features->capabilities |= OFPUTIL_C_STP; } features->ofpacts = ofpact_bitmap_from_openflow(osf->actions, OFP10_VERSION); } else if (raw == OFPRAW_OFPT11_FEATURES_REPLY || raw == OFPRAW_OFPT13_FEATURES_REPLY) { if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) { features->capabilities |= OFPUTIL_C_GROUP_STATS; } features->ofpacts = 0; if (raw == OFPRAW_OFPT13_FEATURES_REPLY) { features->auxiliary_id = osf->auxiliary_id; } } else { return OFPERR_OFPBRC_BAD_VERSION; } return 0; }