/* 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; }
void multipath_parse(struct nx_action_multipath *mp, const char *s_) { char *s = xstrdup(s_); char *save_ptr = NULL; char *fields, *basis, *algorithm, *n_links_str, *arg, *dst_s; struct mf_subfield dst; int n_links; fields = strtok_r(s, ", ", &save_ptr); basis = strtok_r(NULL, ", ", &save_ptr); algorithm = strtok_r(NULL, ", ", &save_ptr); n_links_str = strtok_r(NULL, ", ", &save_ptr); arg = strtok_r(NULL, ", ", &save_ptr); dst_s = strtok_r(NULL, ", ", &save_ptr); if (!dst_s) { ovs_fatal(0, "%s: not enough arguments to multipath action", s_); } ofputil_init_NXAST_MULTIPATH(mp); if (!strcasecmp(fields, "eth_src")) { mp->fields = htons(NX_HASH_FIELDS_ETH_SRC); } else if (!strcasecmp(fields, "symmetric_l4")) { mp->fields = htons(NX_HASH_FIELDS_SYMMETRIC_L4); } else { ovs_fatal(0, "%s: unknown fields `%s'", s_, fields); } mp->basis = htons(atoi(basis)); if (!strcasecmp(algorithm, "modulo_n")) { mp->algorithm = htons(NX_MP_ALG_MODULO_N); } else if (!strcasecmp(algorithm, "hash_threshold")) { mp->algorithm = htons(NX_MP_ALG_HASH_THRESHOLD); } else if (!strcasecmp(algorithm, "hrw")) { mp->algorithm = htons(NX_MP_ALG_HRW); } else if (!strcasecmp(algorithm, "iter_hash")) { mp->algorithm = htons(NX_MP_ALG_ITER_HASH); } else { ovs_fatal(0, "%s: unknown algorithm `%s'", s_, algorithm); } n_links = atoi(n_links_str); if (n_links < 1 || n_links > 65536) { ovs_fatal(0, "%s: n_links %d is not in valid range 1 to 65536", s_, n_links); } mp->max_link = htons(n_links - 1); mp->arg = htonl(atoi(arg)); mf_parse_subfield(&dst, dst_s); if (dst.n_bits < 16 && n_links > (1u << dst.n_bits)) { ovs_fatal(0, "%s: %d-bit destination field has %u possible values, " "less than specified n_links %d", s_, dst.n_bits, 1u << dst.n_bits, n_links); } mp->ofs_nbits = nxm_encode_ofs_nbits(dst.ofs, dst.n_bits); mp->dst = htonl(dst.field->nxm_header); free(s); }
/* Parses 's_' as a set of arguments to the "multipath" action and initializes * 'mp' accordingly. ovs-ofctl(8) describes the format parsed. * * Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string.*/ static char * WARN_UNUSED_RESULT multipath_parse__(struct ofpact_multipath *mp, const char *s_, char *s) { char *save_ptr = NULL; char *fields, *basis, *algorithm, *n_links_str, *arg, *dst; char *error; int n_links; fields = strtok_r(s, ", ", &save_ptr); basis = strtok_r(NULL, ", ", &save_ptr); algorithm = strtok_r(NULL, ", ", &save_ptr); n_links_str = strtok_r(NULL, ", ", &save_ptr); arg = strtok_r(NULL, ", ", &save_ptr); dst = strtok_r(NULL, ", ", &save_ptr); if (!dst) { return xasprintf("%s: not enough arguments to multipath action", s_); } ofpact_init_MULTIPATH(mp); if (!strcasecmp(fields, "eth_src")) { mp->fields = NX_HASH_FIELDS_ETH_SRC; } else if (!strcasecmp(fields, "symmetric_l4")) { mp->fields = NX_HASH_FIELDS_SYMMETRIC_L4; } else { return xasprintf("%s: unknown fields `%s'", s_, fields); } mp->basis = atoi(basis); if (!strcasecmp(algorithm, "modulo_n")) { mp->algorithm = NX_MP_ALG_MODULO_N; } else if (!strcasecmp(algorithm, "hash_threshold")) { mp->algorithm = NX_MP_ALG_HASH_THRESHOLD; } else if (!strcasecmp(algorithm, "hrw")) { mp->algorithm = NX_MP_ALG_HRW; } else if (!strcasecmp(algorithm, "iter_hash")) { mp->algorithm = NX_MP_ALG_ITER_HASH; } else { return xasprintf("%s: unknown algorithm `%s'", s_, algorithm); } n_links = atoi(n_links_str); if (n_links < 1 || n_links > 65536) { return xasprintf("%s: n_links %d is not in valid range 1 to 65536", s_, n_links); } mp->max_link = n_links - 1; mp->arg = atoi(arg); error = mf_parse_subfield(&mp->dst, dst); if (error) { return error; } if (mp->dst.n_bits < 16 && n_links > (1u << mp->dst.n_bits)) { return xasprintf("%s: %d-bit destination field has %u possible " "values, less than specified n_links %d", s_, mp->dst.n_bits, 1u << mp->dst.n_bits, n_links); } 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 parse_output(char *arg, struct ofpbuf *ofpacts) { if (strchr(arg, '[')) { struct ofpact_output_reg *output_reg; output_reg = ofpact_put_OUTPUT_REG(ofpacts); mf_parse_subfield(&output_reg->src, arg); output_reg->max_len = UINT16_MAX; } else { struct ofpact_output *output; output = ofpact_put_OUTPUT(ofpacts); output->port = u16_to_ofp(str_to_u32(arg)); output->max_len = output->port == OFPP_CONTROLLER ? UINT16_MAX : 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_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, struct ofpact_learn_spec *spec) { 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; memset(&spec->src_imm, 0, sizeof spec->src_imm); memcpy(&spec->src_imm.u8[sizeof spec->src_imm - dst->n_bytes], &imm, dst->n_bytes); spec->dst_type = NX_LEARN_DST_MATCH; spec->dst.field = dst; spec->dst.ofs = 0; spec->dst.n_bits = dst->n_bits; } 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); 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; }
static void learn_parse_spec(const char *orig, char *name, char *value, struct ofpact_learn_spec *spec) { 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) { ovs_fatal(0, "%s", error); } spec->n_bits = dst->n_bits; spec->src_type = NX_LEARN_SRC_IMMEDIATE; memset(&spec->src_imm, 0, sizeof spec->src_imm); memcpy(&spec->src_imm.u8[sizeof spec->src_imm - dst->n_bytes], &imm, dst->n_bytes); spec->dst_type = NX_LEARN_DST_MATCH; spec->dst.field = dst; spec->dst.ofs = 0; spec->dst.n_bits = dst->n_bits; } else if (strchr(name, '[')) { /* Parse destination and check prerequisites. */ if (mf_parse_subfield(&spec->dst, name)[0] != '\0') { ovs_fatal(0, "%s: syntax error after NXM field name `%s'", orig, name); } /* Parse source and check prerequisites. */ if (value[0] != '\0') { if (mf_parse_subfield(&spec->src, value)[0] != '\0') { ovs_fatal(0, "%s: syntax error after NXM field name `%s'", orig, value); } if (spec->src.n_bits != spec->dst.n_bits) { ovs_fatal(0, "%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, "[-")] == '-') { learn_parse_load_immediate(value, spec); } else { struct ofpact_reg_move move; nxm_parse_reg_move(&move, value); 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")) { if (mf_parse_subfield(&spec->src, value)[0] != '\0') { ovs_fatal(0, "%s: syntax error after NXM field name `%s'", orig, name); } spec->n_bits = spec->src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->dst_type = NX_LEARN_DST_OUTPUT; } else { ovs_fatal(0, "%s: unknown keyword %s", orig, name); } }
/* 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__(char *orig, char *arg, const struct ofputil_port_map *port_map, struct ofpbuf *ofpacts) { struct ofpact_learn *learn; struct match match; char *name, *value; learn = ofpact_put_LEARN(ofpacts); learn->idle_timeout = OFP_FLOW_PERMANENT; learn->hard_timeout = OFP_FLOW_PERMANENT; learn->priority = OFP_DEFAULT_PRIORITY; learn->table_id = 1; match_init_catchall(&match); while (ofputil_parse_key_value(&arg, &name, &value)) { if (!strcmp(name, "table")) { learn->table_id = atoi(value); if (learn->table_id == 255) { return xasprintf("%s: table id 255 not valid for `learn' " "action", orig); } } else if (!strcmp(name, "priority")) { learn->priority = atoi(value); } else if (!strcmp(name, "idle_timeout")) { learn->idle_timeout = atoi(value); } else if (!strcmp(name, "hard_timeout")) { learn->hard_timeout = atoi(value); } else if (!strcmp(name, "fin_idle_timeout")) { learn->fin_idle_timeout = atoi(value); } else if (!strcmp(name, "fin_hard_timeout")) { learn->fin_hard_timeout = atoi(value); } else if (!strcmp(name, "cookie")) { learn->cookie = htonll(strtoull(value, NULL, 0)); } else if (!strcmp(name, "send_flow_rem")) { learn->flags |= NX_LEARN_F_SEND_FLOW_REM; } else if (!strcmp(name, "delete_learned")) { learn->flags |= NX_LEARN_F_DELETE_LEARNED; } else if (!strcmp(name, "limit")) { learn->limit = atoi(value); } else if (!strcmp(name, "result_dst")) { char *error; learn->flags |= NX_LEARN_F_WRITE_RESULT; error = mf_parse_subfield(&learn->result_dst, value); if (error) { return error; } if (!learn->result_dst.field->writable) { return xasprintf("%s is read-only", value); } if (learn->result_dst.n_bits != 1) { return xasprintf("result_dst in 'learn' action must be a " "single bit"); } } else { struct ofpact_learn_spec *spec; char *error; spec = ofpbuf_put_zeros(ofpacts, sizeof *spec); error = learn_parse_spec(orig, name, value, port_map, spec, ofpacts, &match); if (error) { return error; } learn = ofpacts->header; } } ofpact_finish_LEARN(ofpacts, &learn); 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; }
/* Helper for bundle_parse and bundle_parse_load. * * Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string.*/ static char * WARN_UNUSED_RESULT bundle_parse__(const char *s, char **save_ptr, const char *fields, const char *basis, const char *algorithm, const char *slave_type, const char *dst, const char *slave_delim, struct ofpbuf *ofpacts) { struct ofpact_bundle *bundle; if (!slave_delim) { return xasprintf("%s: not enough arguments to bundle action", s); } if (strcasecmp(slave_delim, "slaves")) { return xasprintf("%s: missing slave delimiter, expected `slaves' " "got `%s'", s, slave_delim); } bundle = ofpact_put_BUNDLE(ofpacts); for (;;) { ofp_port_t slave_port; char *slave; slave = strtok_r(NULL, ", []", save_ptr); if (!slave || bundle->n_slaves >= BUNDLE_MAX_SLAVES) { break; } if (!ofputil_port_from_string(slave, &slave_port)) { return xasprintf("%s: bad port number", slave); } ofpbuf_put(ofpacts, &slave_port, sizeof slave_port); bundle = ofpacts->l2; bundle->n_slaves++; } ofpact_update_len(ofpacts, &bundle->ofpact); bundle->basis = atoi(basis); if (!strcasecmp(fields, "eth_src")) { bundle->fields = NX_HASH_FIELDS_ETH_SRC; } else if (!strcasecmp(fields, "symmetric_l4")) { bundle->fields = NX_HASH_FIELDS_SYMMETRIC_L4; } else { return xasprintf("%s: unknown fields `%s'", s, fields); } if (!strcasecmp(algorithm, "active_backup")) { bundle->algorithm = NX_BD_ALG_ACTIVE_BACKUP; } else if (!strcasecmp(algorithm, "hrw")) { bundle->algorithm = NX_BD_ALG_HRW; } else { return xasprintf("%s: unknown algorithm `%s'", s, algorithm); } if (strcasecmp(slave_type, "ofport")) { return xasprintf("%s: unknown slave_type `%s'", s, slave_type); } if (dst) { char *error = mf_parse_subfield(&bundle->dst, dst); if (error) { return error; } } 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, 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; }
/* Helper for bundle_parse and bundle_parse_load. */ static void bundle_parse__(const char *s, char **save_ptr, const char *fields, const char *basis, const char *algorithm, const char *slave_type, const char *dst, const char *slave_delim, struct ofpbuf *ofpacts) { struct ofpact_bundle *bundle; if (!slave_delim) { ovs_fatal(0, "%s: not enough arguments to bundle action", s); } if (strcasecmp(slave_delim, "slaves")) { ovs_fatal(0, "%s: missing slave delimiter, expected `slaves' got `%s'", s, slave_delim); } bundle = ofpact_put_BUNDLE(ofpacts); for (;;) { uint16_t slave_port; char *slave; slave = strtok_r(NULL, ", [", save_ptr); if (!slave || bundle->n_slaves >= BUNDLE_MAX_SLAVES) { break; } slave_port = atoi(slave); ofpbuf_put(ofpacts, &slave_port, sizeof slave_port); bundle = ofpacts->l2; bundle->n_slaves++; } ofpact_update_len(ofpacts, &bundle->ofpact); bundle->basis = atoi(basis); if (!strcasecmp(fields, "eth_src")) { bundle->fields = NX_HASH_FIELDS_ETH_SRC; } else if (!strcasecmp(fields, "symmetric_l4")) { bundle->fields = NX_HASH_FIELDS_SYMMETRIC_L4; } else { ovs_fatal(0, "%s: unknown fields `%s'", s, fields); } if (!strcasecmp(algorithm, "active_backup")) { bundle->algorithm = NX_BD_ALG_ACTIVE_BACKUP; } else if (!strcasecmp(algorithm, "hrw")) { bundle->algorithm = NX_BD_ALG_HRW; } else { ovs_fatal(0, "%s: unknown algorithm `%s'", s, algorithm); } if (strcasecmp(slave_type, "ofport")) { ovs_fatal(0, "%s: unknown slave_type `%s'", s, slave_type); } if (dst) { mf_parse_subfield(&bundle->dst, dst); } }