-static uint32_t
-vendor_code_to_id(uint8_t code)
-{
- switch (code) {
-#define OFPUTIL_VENDOR(NAME, VENDOR_ID) case NAME: return VENDOR_ID;
- OFPUTIL_VENDORS
-#undef OFPUTIL_VENDOR
- default:
- return UINT32_MAX;
- }
-}
-
-static int
-vendor_id_to_code(uint32_t id)
-{
- switch (id) {
-#define OFPUTIL_VENDOR(NAME, VENDOR_ID) case VENDOR_ID: return NAME;
- OFPUTIL_VENDORS
-#undef OFPUTIL_VENDOR
- default:
- return -1;
- }
-}
-
-/* Creates and returns an OpenFlow message of type OFPT_ERROR with the error
- * information taken from 'error', whose encoding must be as described in the
- * large comment in ofp-util.h. If 'oh' is nonnull, then the error will use
- * oh->xid as its transaction ID, and it will include up to the first 64 bytes
- * of 'oh'.
- *
- * Returns NULL if 'error' is not an OpenFlow error code. */
-struct ofpbuf *
-ofputil_encode_error_msg(int error, const struct ofp_header *oh)
-{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-
- struct ofpbuf *buf;
- const void *data;
- size_t len;
- uint8_t vendor;
- uint16_t type;
- uint16_t code;
- ovs_be32 xid;
-
- if (!is_ofp_error(error)) {
- /* We format 'error' with strerror() here since it seems likely to be
- * a system errno value. */
- VLOG_WARN_RL(&rl, "invalid OpenFlow error code %d (%s)",
- error, strerror(error));
- return NULL;
- }
-
- if (oh) {
- xid = oh->xid;
- data = oh;
- len = ntohs(oh->length);
- if (len > 64) {
- len = 64;
- }
- } else {
- xid = 0;
- data = NULL;
- len = 0;
- }
-
- vendor = get_ofp_err_vendor(error);
- type = get_ofp_err_type(error);
- code = get_ofp_err_code(error);
- if (vendor == OFPUTIL_VENDOR_OPENFLOW) {
- struct ofp_error_msg *oem;
-
- oem = make_openflow_xid(len + sizeof *oem, OFPT_ERROR, xid, &buf);
- oem->type = htons(type);
- oem->code = htons(code);
- } else {
- struct ofp_error_msg *oem;
- struct nx_vendor_error *nve;
- uint32_t vendor_id;
-
- vendor_id = vendor_code_to_id(vendor);
- if (vendor_id == UINT32_MAX) {
- VLOG_WARN_RL(&rl, "error %x contains invalid vendor code %d",
- error, vendor);
- return NULL;
- }
-
- oem = make_openflow_xid(len + sizeof *oem + sizeof *nve,
- OFPT_ERROR, xid, &buf);
- oem->type = htons(NXET_VENDOR);
- oem->code = htons(NXVC_VENDOR_ERROR);
-
- nve = (struct nx_vendor_error *)oem->data;
- nve->vendor = htonl(vendor_id);
- nve->type = htons(type);
- nve->code = htons(code);
- }
-
- if (len) {
- buf->size -= len;
- ofpbuf_put(buf, data, len);
- }
-
- return buf;
-}
-
-/* Decodes 'oh', which should be an OpenFlow OFPT_ERROR message, and returns an
- * Open vSwitch internal error code in the format described in the large
- * comment in ofp-util.h.
- *
- * If 'payload_ofs' is nonnull, on success '*payload_ofs' is set to the offset
- * to the payload starting from 'oh' and on failure it is set to 0. */
-int
-ofputil_decode_error_msg(const struct ofp_header *oh, size_t *payload_ofs)
-{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-
- const struct ofp_error_msg *oem;
- uint16_t type, code;
- struct ofpbuf b;
- int vendor;
-
- if (payload_ofs) {
- *payload_ofs = 0;
- }
- if (oh->type != OFPT_ERROR) {
- return EPROTO;
- }
-
- ofpbuf_use_const(&b, oh, ntohs(oh->length));
- oem = ofpbuf_try_pull(&b, sizeof *oem);
- if (!oem) {
- return EPROTO;
- }
-
- type = ntohs(oem->type);
- code = ntohs(oem->code);
- if (type == NXET_VENDOR && code == NXVC_VENDOR_ERROR) {
- const struct nx_vendor_error *nve = ofpbuf_try_pull(&b, sizeof *nve);
- if (!nve) {
- return EPROTO;
- }
-
- vendor = vendor_id_to_code(ntohl(nve->vendor));
- if (vendor < 0) {
- VLOG_WARN_RL(&rl, "error contains unknown vendor ID %#"PRIx32,
- ntohl(nve->vendor));
- return EPROTO;
- }
- type = ntohs(nve->type);
- code = ntohs(nve->code);
- } else {
- vendor = OFPUTIL_VENDOR_OPENFLOW;
- }
-
- if (type >= 1024) {
- VLOG_WARN_RL(&rl, "error contains type %"PRIu16" greater than "
- "supported maximum value 1023", type);
- return EPROTO;
- }
-
- if (payload_ofs) {
- *payload_ofs = (uint8_t *) b.data - (uint8_t *) oh;
- }
- return ofp_mkerr_vendor(vendor, type, code);
-}
-
-void
-ofputil_format_error(struct ds *s, int error)
-{
- if (is_errno(error)) {
- ds_put_cstr(s, strerror(error));
- } else {
- uint16_t type = get_ofp_err_type(error);
- uint16_t code = get_ofp_err_code(error);
- const char *type_s = ofp_error_type_to_string(type);
- const char *code_s = ofp_error_code_to_string(type, code);
-
- ds_put_format(s, "type ");
- if (type_s) {
- ds_put_cstr(s, type_s);
- } else {
- ds_put_format(s, "%"PRIu16, type);
- }
-
- ds_put_cstr(s, ", code ");
- if (code_s) {
- ds_put_cstr(s, code_s);
- } else {
- ds_put_format(s, "%"PRIu16, code);
- }
- }
-}
-
-char *
-ofputil_error_to_string(int error)
-{
- struct ds s = DS_EMPTY_INITIALIZER;
- ofputil_format_error(&s, error);
- return ds_steal_cstr(&s);
-}
-
-/* Attempts to pull 'actions_len' bytes from the front of 'b'. Returns 0 if
- * successful, otherwise an OpenFlow error.
- *
- * 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". */
-int
-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 ofp_mkerr(OFPET_BAD_REQUEST, 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;
-}
-