/* 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_load_immediate(const char *s, struct ofpact_learn_spec *spec, struct ofpbuf *ofpacts) { const char *full_s = s; struct mf_subfield dst; union mf_subvalue imm; char *error; int err; err = parse_int_string(s, imm.u8, sizeof imm.u8, (char **) &s); if (err) { return xasprintf("%s: too many bits in immediate value", full_s); } if (strncmp(s, "->", 2)) { return xasprintf("%s: missing `->' following value", full_s); } s += 2; error = mf_parse_subfield(&dst, s); if (error) { return error; } if (!mf_nxm_header(dst.field->id)) { return xasprintf("%s: experimenter OXM field '%s' not supported", full_s, s); } if (!bitwise_is_all_zeros(&imm, sizeof imm, dst.n_bits, (8 * sizeof imm) - dst.n_bits)) { return xasprintf("%s: value does not fit into %u bits", full_s, dst.n_bits); } spec->n_bits = dst.n_bits; spec->src_type = NX_LEARN_SRC_IMMEDIATE; spec->dst_type = NX_LEARN_DST_LOAD; spec->dst = dst; /* Push value last, as this may reallocate 'spec'! */ unsigned int n_bytes = DIV_ROUND_UP(dst.n_bits, 8); uint8_t *src_imm = ofpbuf_put_zeros(ofpacts, OFPACT_ALIGN(n_bytes)); memcpy(src_imm, &imm.u8[sizeof imm.u8 - n_bytes], n_bytes); return NULL; }
/* 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_load_immediate(const char *s, struct ofpact_learn_spec *spec) { const char *full_s = s; struct mf_subfield dst; union mf_subvalue imm; char *error; int err; err = parse_int_string(s, imm.u8, sizeof imm.u8, (char **) &s); if (err) { return xasprintf("%s: too many bits in immediate value", full_s); } if (strncmp(s, "->", 2)) { return xasprintf("%s: missing `->' following value", full_s); } s += 2; error = mf_parse_subfield(&dst, s); if (error) { return error; } if (!mf_nxm_header(dst.field->id)) { return xasprintf("%s: experimenter OXM field '%s' not supported", full_s, s); } if (!bitwise_is_all_zeros(&imm, sizeof imm, dst.n_bits, (8 * sizeof imm) - dst.n_bits)) { return xasprintf("%s: value does not fit into %u bits", full_s, dst.n_bits); } spec->n_bits = dst.n_bits; spec->src_type = NX_LEARN_SRC_IMMEDIATE; spec->src_imm = imm; spec->dst_type = NX_LEARN_DST_LOAD; spec->dst = dst; return NULL; }
/* 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, const struct ofputil_port_map *port_map, struct ofpact_learn_spec *spec, struct ofpbuf *ofpacts, struct match *match) { /* Parse destination and check prerequisites. */ struct mf_subfield dst; char *error = mf_parse_subfield(&dst, name); bool parse_error = error != NULL; free(error); if (!parse_error) { if (!mf_nxm_header(dst.field->id)) { return xasprintf("%s: experimenter OXM field '%s' not supported", orig, name); } spec->dst = dst; spec->n_bits = dst.n_bits; spec->dst_type = NX_LEARN_DST_MATCH; /* Parse source and check prerequisites. */ if (value[0] != '\0') { struct mf_subfield src; error = mf_parse_subfield(&src, value); if (error) { union mf_value imm; char *imm_error = NULL; /* Try an immediate value. */ if (dst.ofs == 0 && dst.n_bits == dst.field->n_bits) { /* Full field value. */ imm_error = mf_parse_value(dst.field, value, port_map, &imm); } else { char *tail; /* Partial field value. */ if (parse_int_string(value, (uint8_t *)&imm, dst.field->n_bytes, &tail) || *tail != 0) { imm_error = xasprintf("%s: cannot parse integer value", orig); } if (!imm_error && !bitwise_is_all_zeros(&imm, dst.field->n_bytes, dst.n_bits, dst.field->n_bytes * 8 - dst.n_bits)) { struct ds ds; ds_init(&ds); mf_format(dst.field, &imm, NULL, NULL, &ds); imm_error = xasprintf("%s: value %s does not fit into %d bits", orig, ds_cstr(&ds), dst.n_bits); ds_destroy(&ds); } } if (imm_error) { char *err = xasprintf("%s: %s value %s cannot be parsed as a subfield (%s) or an immediate value (%s)", orig, name, value, error, imm_error); free(error); free(imm_error); return err; } spec->src_type = NX_LEARN_SRC_IMMEDIATE; /* Update 'match' to allow for satisfying destination * prerequisites. */ mf_write_subfield_value(&dst, &imm, match); /* Push value last, as this may reallocate 'spec'! */ unsigned int imm_bytes = DIV_ROUND_UP(dst.n_bits, 8); uint8_t *src_imm = ofpbuf_put_zeros(ofpacts, OFPACT_ALIGN(imm_bytes)); memcpy(src_imm, &imm, imm_bytes); free(error); return NULL; } spec->src = src; 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->src_type = NX_LEARN_SRC_FIELD; } else if (!strcmp(name, "load")) { union mf_subvalue imm; char *tail; char *dst_value = strstr(value, "->"); if (dst_value == value) { return xasprintf("%s: missing source before `->' in `%s'", name, value); } if (!dst_value) { return xasprintf("%s: missing `->' in `%s'", name, value); } if (!parse_int_string(value, imm.u8, sizeof imm.u8, (char **) &tail) && tail != value) { if (tail != dst_value) { return xasprintf("%s: garbage before `->' in `%s'", name, value); } error = learn_parse_load_immediate(&imm, dst_value + 2, value, spec, ofpacts); if (error) { return error; } } else { struct ofpact_reg_move move; 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")) { 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; }