/* 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(union mf_subvalue *imm, const char *s, const char *full_s, struct ofpact_learn_spec *spec, struct ofpbuf *ofpacts) { struct mf_subfield dst; char *error; 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; const char *arrow = strstr(s, "->"); struct mf_subfield dst; union mf_subvalue imm; char *error; memset(&imm, 0, sizeof imm); if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && arrow) { const char *in = arrow - 1; uint8_t *out = imm.u8 + sizeof imm.u8 - 1; int n = arrow - (s + 2); int i; for (i = 0; i < n; i++) { int hexit = hexit_value(in[-i]); if (hexit < 0) { return xasprintf("%s: bad hex digit in value", full_s); } out[-(i / 2)] |= i % 2 ? hexit << 4 : hexit; } s = arrow; } else { ovs_be64 *last_be64 = &imm.be64[ARRAY_SIZE(imm.be64) - 1]; *last_be64 = htonll(strtoull(s, (char **) &s, 0)); } 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; }
static void learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec) { const char *full_s = s; const char *arrow = strstr(s, "->"); struct mf_subfield dst; union mf_subvalue imm; memset(&imm, 0, sizeof imm); if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && arrow) { const char *in = arrow - 1; uint8_t *out = imm.u8 + sizeof imm.u8 - 1; int n = arrow - (s + 2); int i; for (i = 0; i < n; i++) { int hexit = hexit_value(in[-i]); if (hexit < 0) { ovs_fatal(0, "%s: bad hex digit in value", full_s); } out[-(i / 2)] |= i % 2 ? hexit << 4 : hexit; } s = arrow; } else { imm.be64[1] = htonll(strtoull(s, (char **) &s, 0)); } if (strncmp(s, "->", 2)) { ovs_fatal(0, "%s: missing `->' following value", full_s); } s += 2; s = mf_parse_subfield(&dst, s); if (*s != '\0') { ovs_fatal(0, "%s: trailing garbage following destination", full_s); } if (!bitwise_is_all_zeros(&imm, sizeof imm, dst.n_bits, (8 * sizeof imm) - dst.n_bits)) { ovs_fatal(0, "%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; }
static void check_bitwise_is_all_zeros(void) { int n_loops; n_loops = 0; for (n_loops = 0; n_loops < 100; n_loops++) { ovs_be64 x = htonll(0); int i; for (i = 0; i < 64; i++) { ovs_be64 bit; int ofs, n; /* Change a random 0-bit into a 1-bit. */ do { bit = htonll(UINT64_C(1) << (random_uint32() % 64)); } while (x & bit); x |= bit; for (ofs = 0; ofs < 64; ofs++) { for (n = 0; n <= 64 - ofs; n++) { bool expect; bool answer; expect = (n == 64 ? x == 0 : !(x & htonll(((UINT64_C(1) << n) - 1) << ofs))); answer = bitwise_is_all_zeros(&x, sizeof x, ofs, n); if (expect != answer) { fprintf(stderr, "bitwise_is_all_zeros(0x%016"PRIx64",8,%d,%d " "returned %s instead of %s\n", ntohll(x), ofs, n, answer ? "true" : "false", expect ? "true" : "false"); abort(); } } } } } }
/* 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; }