static enum ofperr nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask) { uint32_t header; ovs_assert((cookie != NULL) == (cookie_mask != NULL)); match_init_catchall(match); if (cookie) { *cookie = *cookie_mask = htonll(0); } if (!match_len) { return 0; } for (; (header = nx_entry_ok(p, match_len)) != 0; p += 4 + NXM_LENGTH(header), match_len -= 4 + NXM_LENGTH(header)) { const struct mf_field *mf; enum ofperr error; mf = mf_from_nxm_header(header); if (!mf) { if (strict) { error = OFPERR_OFPBMC_BAD_FIELD; } else { continue; } } else if (!mf_are_prereqs_ok(mf, &match->flow)) { error = OFPERR_OFPBMC_BAD_PREREQ; } else if (!mf_is_all_wild(mf, &match->wc)) { error = OFPERR_OFPBMC_DUP_FIELD; } else { unsigned int width = mf->n_bytes; union mf_value value; memcpy(&value, p + 4, width); if (!mf_is_value_valid(mf, &value)) { error = OFPERR_OFPBMC_BAD_VALUE; } else if (!NXM_HASMASK(header)) { error = 0; mf_set_value(mf, &value, match); } else { union mf_value mask; memcpy(&mask, p + 4 + width, width); if (!mf_is_mask_valid(mf, &mask)) { error = OFPERR_OFPBMC_BAD_MASK; } else { error = check_mask_consistency(p, mf); if (!error) { mf_set(mf, &value, &mask, match); } } } } /* Check if the match is for a cookie rather than a classifier rule. */ if ((header == NXM_NX_COOKIE || header == NXM_NX_COOKIE_W) && cookie) { if (*cookie_mask) { error = OFPERR_OFPBMC_DUP_FIELD; } else { unsigned int width = sizeof *cookie; memcpy(cookie, p + 4, width); if (NXM_HASMASK(header)) { memcpy(cookie_mask, p + 4 + width, width); } else { *cookie_mask = OVS_BE64_MAX; } error = 0; } } if (error) { VLOG_DBG_RL(&rl, "bad nxm_entry %#08"PRIx32" (vendor=%"PRIu32", " "field=%"PRIu32", hasmask=%"PRIu32", len=%"PRIu32"), " "(%s)", header, NXM_VENDOR(header), NXM_FIELD(header), NXM_HASMASK(header), NXM_LENGTH(header), ofperr_to_string(error)); return error; } } return match_len ? OFPERR_OFPBMC_BAD_LEN : 0; }
/* Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ static char * OVS_WARN_UNUSED_RESULT learn_parse_spec(const char *orig, char *name, char *value, struct ofpact_learn_spec *spec, struct ofpbuf *ofpacts, struct match *match) { if (mf_from_name(name)) { const struct mf_field *dst = mf_from_name(name); union mf_value imm; char *error; error = mf_parse_value(dst, value, &imm); if (error) { return error; } spec->n_bits = dst->n_bits; spec->src_type = NX_LEARN_SRC_IMMEDIATE; spec->dst_type = NX_LEARN_DST_MATCH; spec->dst.field = dst; spec->dst.ofs = 0; spec->dst.n_bits = dst->n_bits; /* Update 'match' to allow for satisfying destination * prerequisites. */ mf_set_value(dst, &imm, match, NULL); /* Push value last, as this may reallocate 'spec'! */ uint8_t *src_imm = ofpbuf_put_zeros(ofpacts, OFPACT_ALIGN(dst->n_bytes)); memcpy(src_imm, &imm, dst->n_bytes); } else if (strchr(name, '[')) { /* Parse destination and check prerequisites. */ char *error; error = mf_parse_subfield(&spec->dst, name); if (error) { return error; } if (!mf_nxm_header(spec->dst.field->id)) { return xasprintf("%s: experimenter OXM field '%s' not supported", orig, name); } /* Parse source and check prerequisites. */ if (value[0] != '\0') { error = mf_parse_subfield(&spec->src, value); if (error) { return error; } if (spec->src.n_bits != spec->dst.n_bits) { return xasprintf("%s: bit widths of %s (%u) and %s (%u) " "differ", orig, name, spec->src.n_bits, value, spec->dst.n_bits); } } else { spec->src = spec->dst; } spec->n_bits = spec->src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->dst_type = NX_LEARN_DST_MATCH; } else if (!strcmp(name, "load")) { if (value[strcspn(value, "[-")] == '-') { char *error = learn_parse_load_immediate(value, spec, ofpacts); if (error) { return error; } } else { struct ofpact_reg_move move; char *error; error = nxm_parse_reg_move(&move, value); if (error) { return error; } spec->n_bits = move.src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->src = move.src; spec->dst_type = NX_LEARN_DST_LOAD; spec->dst = move.dst; } } else if (!strcmp(name, "output")) { char *error = mf_parse_subfield(&spec->src, value); if (error) { return error; } spec->n_bits = spec->src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->dst_type = NX_LEARN_DST_OUTPUT; } else { return xasprintf("%s: unknown keyword %s", orig, name); } return NULL; }