/* 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; }
static int ofputil_pull_queue_get_config_reply14(struct ofpbuf *msg, struct ofputil_queue_config *queue) { struct ofp14_queue_desc *oqd14 = ofpbuf_try_pull(msg, sizeof *oqd14); if (!oqd14) { return OFPERR_OFPBRC_BAD_LEN; } enum ofperr error = ofputil_port_from_ofp11(oqd14->port_no, &queue->port); if (error) { return error; } queue->queue = ntohl(oqd14->queue_id); /* Length check. */ unsigned int len = ntohs(oqd14->len); if (len < sizeof *oqd14 || len > msg->size + sizeof *oqd14 || len % 8) { return OFPERR_OFPBRC_BAD_LEN; } len -= sizeof *oqd14; struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len), len); while (properties.size > 0) { struct ofpbuf payload; uint64_t type; error = ofpprop_pull(&properties, &payload, &type); if (error) { return error; } switch (type) { case OFPQDPT14_MIN_RATE: error = ofpprop_parse_u16(&payload, &queue->min_rate); break; case OFPQDPT14_MAX_RATE: error = ofpprop_parse_u16(&payload, &queue->max_rate); break; default: error = OFPPROP_UNKNOWN(true, "queue desc", type); break; } if (error) { return error; } } return 0; }
/* Tries to decode 'oh', which should be an OpenFlow OFPT_ERROR message. * Returns an OFPERR_* constant on success, 0 on failure. * * If 'payload' is nonnull, on success '*payload' is initialized with a copy of * the error's payload (copying is required because the payload is not properly * aligned). The caller must free the payload (with ofpbuf_uninit()) when it * is no longer needed. On failure, '*payload' is cleared. */ enum ofperr ofperr_decode_msg(const struct ofp_header *oh, struct ofpbuf *payload) { const struct ofp_error_msg *oem; enum ofpraw raw; uint16_t type, code; uint32_t vendor; if (payload) { memset(payload, 0, sizeof *payload); } /* Pull off the error message. */ struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); enum ofperr error = ofpraw_pull(&raw, &b); if (error) { return 0; } oem = ofpbuf_pull(&b, sizeof *oem); /* Get the error type and code. */ vendor = 0; type = ntohs(oem->type); code = ntohs(oem->code); if (type == NXET_VENDOR && code == NXVC_VENDOR_ERROR) { const struct nx_vendor_error *nve = ofpbuf_try_pull(&b, sizeof *nve); if (!nve) { return 0; } vendor = ntohl(nve->vendor); type = ntohs(nve->type); code = ntohs(nve->code); } else if (type == OFPET12_EXPERIMENTER) { const ovs_be32 *vendorp = ofpbuf_try_pull(&b, sizeof *vendorp); if (!vendorp) { return 0; } vendor = ntohl(*vendorp); type = code; code = 0; } /* Translate the error type and code into an ofperr. */ error = ofperr_decode(oh->version, vendor, type, code); if (error && payload) { ofpbuf_init(payload, b.size); ofpbuf_push(payload, b.data, b.size); } return error; }
/* 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_queue_get_config_reply_format(struct ds *string, const struct ofp_header *oh, const struct ofputil_port_map *port_map) { struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); struct ofputil_queue_config *queues = NULL; size_t allocated_queues = 0; size_t n = 0; int retval = 0; for (;;) { if (n >= allocated_queues) { queues = x2nrealloc(queues, &allocated_queues, sizeof *queues); } retval = ofputil_pull_queue_get_config_reply(&b, &queues[n]); if (retval) { break; } n++; } qsort(queues, n, sizeof *queues, compare_queues); ds_put_char(string, ' '); ofp_port_t port = 0; for (const struct ofputil_queue_config *q = queues; q < &queues[n]; q++) { if (q->port != port) { port = q->port; ds_put_cstr(string, "port="); ofputil_format_port(port, port_map, string); ds_put_char(string, '\n'); } ds_put_format(string, "queue %"PRIu32":", q->queue); print_queue_rate(string, "min_rate", q->min_rate); print_queue_rate(string, "max_rate", q->max_rate); ds_put_char(string, '\n'); } ds_chomp(string, ' '); free(queues); return retval != EOF ? retval : 0; }
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; }
static enum ofperr process_switch_features(struct lswitch *sw, struct ofp_header *oh) { struct ofputil_switch_features features; struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); enum ofperr error = ofputil_pull_switch_features(&b, &features); if (error) { VLOG_ERR("received invalid switch feature reply (%s)", ofperr_to_string(error)); return error; } sw->datapath_id = features.datapath_id; return 0; }
enum ofperr ofputil_queue_stats_reply_format(struct ds *string, const struct ofp_header *oh, const struct ofputil_port_map *port_map, int verbosity) { ds_put_format(string, " %"PRIuSIZE" queues\n", ofputil_count_queue_stats(oh)); if (verbosity < 1) { return 0; } struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); for (;;) { struct ofputil_queue_stats qs; int retval; retval = ofputil_decode_queue_stats(&qs, &b); if (retval) { return retval != EOF ? retval : 0; } ds_put_cstr(string, " port "); ofputil_format_port(qs.port_no, port_map, string); ds_put_cstr(string, " queue "); ofp_print_queue_name(string, qs.queue_id); ds_put_cstr(string, ": "); print_queue_stat(string, "bytes=", qs.tx_bytes, 1); print_queue_stat(string, "pkts=", qs.tx_packets, 1); print_queue_stat(string, "errors=", qs.tx_errors, 1); ds_put_cstr(string, "duration="); if (qs.duration_sec != UINT32_MAX) { ofp_print_duration(string, qs.duration_sec, qs.duration_nsec); } else { ds_put_char(string, '?'); } ds_put_char(string, '\n'); } }
/* 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); }
static int netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info *info, struct ofpbuf *buf) { static const struct nl_policy ovs_netdev_policy[] = { [OVS_WIN_NETDEV_ATTR_PORT_NO] = { .type = NL_A_U32 }, [OVS_WIN_NETDEV_ATTR_TYPE] = { .type = NL_A_U32 }, [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ }, [OVS_WIN_NETDEV_ATTR_MAC_ADDR] = { NL_POLICY_FOR(info->mac_address) }, [OVS_WIN_NETDEV_ATTR_MTU] = { .type = NL_A_U32 }, [OVS_WIN_NETDEV_ATTR_IF_FLAGS] = { .type = NL_A_U32 }, }; netdev_windows_info_init(info); struct ofpbuf b = ofpbuf_const_initializer(buf->data, buf->size); struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg); struct genlmsghdr *genl = ofpbuf_try_pull(&b, sizeof *genl); struct ovs_header *ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header); struct nlattr *a[ARRAY_SIZE(ovs_netdev_policy)]; if (!nlmsg || !genl || !ovs_header || nlmsg->nlmsg_type != ovs_win_netdev_family || !nl_policy_parse(&b, 0, ovs_netdev_policy, a, ARRAY_SIZE(ovs_netdev_policy))) { return EINVAL; } info->cmd = genl->cmd; info->dp_ifindex = ovs_header->dp_ifindex; info->port_no = nl_attr_get_odp_port(a[OVS_WIN_NETDEV_ATTR_PORT_NO]);