Hey Ben, Have comments inline,
diff --git a/lib/meta-flow.c b/lib/meta-flow.c > index 0677202..e66987c 100644 > --- a/lib/meta-flow.c > +++ b/lib/meta-flow.c > @@ -2699,21 +2699,22 @@ mf_parse_subfield__(struct mf_subfield *sf, const > char **sp) > /* Parses a subfield from the beginning of 's' into 'sf'. Returns the > first > * byte in 's' following the parsed string. > * > - * Exits with an error message if 's' has incorrect syntax. > + * Returns NULL if successful, otherwise a malloc()'d string describing > the > + * error. The caller is responsible for freeing the returned string. > * > The comment " Returns the first byte in 's' following the parsed string." should be removed. > void > diff --git a/lib/meta-flow.h b/lib/meta-flow.h > index a85a193..bc402dc 100644 > --- a/lib/meta-flow.h > +++ b/lib/meta-flow.h > @@ -360,8 +360,10 @@ uint64_t mf_get_subfield(const struct mf_subfield *, > const struct flow *); > > > void mf_format_subfield(const struct mf_subfield *, struct ds *); > -char *mf_parse_subfield__(struct mf_subfield *sf, const char **s); > -const char *mf_parse_subfield(struct mf_subfield *, const char *); > +char *mf_parse_subfield__(struct mf_subfield *sf, const char **s) > + WARN_UNUSED_RESULT; > +char *mf_parse_subfield(struct mf_subfield *, const char *s) > + WARN_UNUSED_RESULT; > > The function attribute "WARN_UNUSED_RESULT" should be added to "mf_parse_subfield__()" in "meta-flow.c" diff --git a/lib/nx-match.c b/lib/nx-match.c index 8bdd8ec..3a6d7cc 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c > +char * WARN_UNUSED_RESULT > nxm_parse_stack_action(struct ofpact_stack *stack_action, const char *s) > { > - s = mf_parse_subfield(&stack_action->subfield, s); > + char *error; > + > + error = mf_parse_subfield__(&stack_action->subfield, &s); > + if (error) { > + return error; > + } > + > if (*s != '\0') { > - ovs_fatal(0, "%s: trailing garbage following push or pop", s); > + return xasprintf("%s: trailing garbage following push or pop", s); > } > + > + return NULL; > } > Is the check "trailing garbage" error message very important? If not, we could just use "mf_parse_subfield()" and remove that check. diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c > index da36f88..ced6bcd 100644 > --- a/lib/ofp-parse.c > +++ b/lib/ofp-parse.c > @@ -41,123 +41,196 @@ > > VLOG_DEFINE_THIS_MODULE(ofp_parse); > > -static void ofp_fatal(const char *flow, bool verbose, const char *format, > ...) > - NO_RETURN; > > -static uint16_t > +str_to_u8(const char *str, const char *name, uint8_t *valuep) > Would you like to swap the "str_to_u16()" and "str_to_u8()"? so that it goes in increasing order of bits of uint. > -static void > +/* Parses 'arg' as the argument to an "enqueue" action, and appends such > an > + * action to 'ofpacts'. > + * > + * 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 > parse_enqueue(char *arg, struct ofpbuf *ofpacts) > { > char *sp = NULL; > char *port = strtok_r(arg, ":q", &sp); > char *queue = strtok_r(NULL, "", &sp); > struct ofpact_enqueue *enqueue; > + char *error; > > if (port == NULL || queue == NULL) { > - ovs_fatal(0, "\"enqueue\" syntax is \"enqueue:PORT:QUEUE\""); > + return xstrdup("\"enqueue\" syntax is \"enqueue:PORT:QUEUE\""); > } > > enqueue = ofpact_put_ENQUEUE(ofpacts); > - enqueue->port = u16_to_ofp(str_to_u32(port)); > - enqueue->queue = str_to_u32(queue); > + if (!ofputil_port_from_string(port, &enqueue->port)) { > + return xasprintf("%s: enqueue to unknown port", port); > + } > + if (!error) { > + error = str_to_u32(queue, &enqueue->queue); > + } > + return error; > } > The pointer error is not initialized, should remove the if statement and return just "str_to_u32(queue, &enqueue->queue)". > -static void > +/* Parses 'arg' as the argument to instruction 'type', and appends such an > + * instruction to 'ofpacts'. > + * > + * 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 > parse_named_instruction(enum ovs_instruction_type type, > char *arg, struct ofpbuf *ofpacts) > { > enum ofperr error; > + char *error_s; > > switch (type) { > case OVSINST_OFPIT11_APPLY_ACTIONS: > @@ -698,28 +922,33 @@ parse_named_instruction(enum ovs_instruction_type > type, > > case OVSINST_OFPIT11_WRITE_ACTIONS: > /* XXX */ > - ovs_fatal(0, "instruction write-actions is not supported yet"); > - break; > + return xstrdup("instruction write-actions is not supported yet"); > > case OVSINST_OFPIT11_CLEAR_ACTIONS: > ofpact_put_CLEAR_ACTIONS(ofpacts); > break; > > case OVSINST_OFPIT13_METER: > - ofpact_put_METER(ofpacts)->meter_id = str_to_u32(arg); > + error_s = str_to_u32(arg, &ofpact_put_METER(ofpacts)->meter_id); > break; > > case OVSINST_OFPIT11_WRITE_METADATA: > - parse_metadata(ofpacts, arg); > + error_s = parse_metadata(ofpacts, arg); > + if (error_s) { > + return error_s; > + } > break; > > case OVSINST_OFPIT11_GOTO_TABLE: { > struct ofpact_goto_table *ogt = ofpact_put_GOTO_TABLE(ofpacts); > char *table_s = strsep(&arg, ","); > if (!table_s || !table_s[0]) { > - ovs_fatal(0, "instruction goto-table needs table id"); > + return xstrdup("instruction goto-table needs table id"); > + } > + error_s = str_to_u8(table_s, "table", &ogt->table_id); > + if (error_s) { > + return error_s; > } > - ogt->table_id = str_to_u8(table_s, "table"); > break; > } > } > 1. Could you explain why the last case "OVSINST_OFPIT11_GOTO_TABLE" is enclosed by curly bracket? 2. For the case "OVSINST_OFPIT13_METER", there is no check for error. 3. Could we move the error check outside the switch statement? Will shorten the code. > @@ -913,13 +1140,13 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int > command, const char *str_, > if (fields & F_ACTIONS) { > act_str = strstr(string, "action"); > if (!act_str) { > - ofp_fatal(str_, verbose, "must specify an action"); > + return xasprintf("must specify an action"); > } > *act_str = '\0'; > > act_str = strchr(act_str + 1, '='); > if (!act_str) { > - ofp_fatal(str_, verbose, "must specify an action"); > + return xasprintf("must specify an action"); > } > > Could you use "xstrdup()" here? since previously, if there is no formatting, we always use "xstrdup()". > @@ -948,44 +1176,50 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int > command, const char *str_, > > value = strtok_r(NULL, ", \t\r\n", &save_ptr); > if (!value) { > - ofp_fatal(str_, verbose, "field %s missing value", name); > + return xasprintf("field %s missing value", name); > } > > if (!strcmp(name, "table")) { > - fm->table_id = str_to_u8(value, name); > + error = str_to_u8(value, "table", &fm->table_id); > } else if (!strcmp(name, "out_port")) { > if (!ofputil_port_from_string(value, &fm->out_port)) { > - ofp_fatal(str_, verbose, "%s is not a valid OpenFlow > port", > - name); > + error = xasprintf("%s is not a valid OpenFlow port", > + value); > } > } else if (fields & F_PRIORITY && !strcmp(name, "priority")) { > - fm->priority = str_to_u16(value, name); > + uint16_t priority; > + > + error = str_to_u16(value, name, &priority); > + fm->priority = priority; > } else if (fields & F_TIMEOUT && !strcmp(name, > "idle_timeout")) { > - fm->idle_timeout = str_to_u16(value, name); > + error = str_to_u16(value, name, &fm->idle_timeout); > } else if (fields & F_TIMEOUT && !strcmp(name, > "hard_timeout")) { > - fm->hard_timeout = str_to_u16(value, name); > + error = str_to_u16(value, name, &fm->hard_timeout); > } else if (!strcmp(name, "cookie")) { > char *mask = strchr(value, '/'); > > if (mask) { > /* A mask means we're searching for a cookie. */ > if (command == OFPFC_ADD) { > - ofp_fatal(str_, verbose, "flow additions cannot > use " > - "a cookie mask"); > + return xstrdup("flow additions cannot use " > + "a cookie mask"); > } > *mask = '\0'; > - fm->cookie = htonll(str_to_u64(value)); > - fm->cookie_mask = htonll(str_to_u64(mask+1)); > + error = str_to_be64(value, &fm->cookie); > + if (error) { > + return error; > + } > + error = str_to_be64(mask + 1, &fm->cookie_mask); > } else { > /* No mask means that the cookie is being set. */ > if (command != OFPFC_ADD && command != OFPFC_MODIFY > - && command != OFPFC_MODIFY_STRICT) { > - ofp_fatal(str_, verbose, "cannot set cookie"); > + && command != OFPFC_MODIFY_STRICT) { > + return xstrdup("cannot set cookie"); > } > - fm->new_cookie = htonll(str_to_u64(value)); > + error = str_to_be64(value, &fm->new_cookie); > } > } else if (mf_from_name(name)) { > - parse_field(mf_from_name(name), value, &fm->match); > + error = parse_field(mf_from_name(name), value, > &fm->match); > } else if (!strcmp(name, "duration") > || !strcmp(name, "n_packets") > || !strcmp(name, "n_bytes") > @@ -995,12 +1229,16 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int > command, const char *str_, > * "ovs-ofctl dump-flows" back into commands that parse > * flows. */ > } else { > - ofp_fatal(str_, verbose, "unknown keyword %s", name); > + error = xasprintf("unknown keyword %s", name); > + } > + > + if (error) { > + return error; > } > } > } > Just want to ask and make sure that there will not be multiple hits in the if-else-if statement above, right? +char * WARN_UNUSED_RESULT > parse_ofp_flow_mod_file(const char *file_name, uint16_t command, > struct ofputil_flow_mod **fms, size_t *n_fms) > { > size_t allocated_fms; > + int line_number; > FILE *stream; > struct ds s; > > + *fms = NULL; > + *n_fms = 0; > + > stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r"); > if (stream == NULL) { > - ovs_fatal(errno, "%s: open", file_name); > + return xasprintf("%s: open failed (%s)", file_name, > strerror(errno)); > } > > allocated_fms = *n_fms; > ds_init(&s); > - while (!ds_get_preprocessed_line(&s, stream)) { > + line_number = 0; > + while (!ds_get_preprocessed_line(&s, stream, &line_number)) { > + char *error; > + > if (*n_fms >= allocated_fms) { > *fms = x2nrealloc(*fms, &allocated_fms, sizeof **fms); > } > - parse_ofp_flow_mod_str(&(*fms)[*n_fms], ds_cstr(&s), command, > false); > + error = parse_ofp_flow_mod_str(&(*fms)[*n_fms], ds_cstr(&s), > command); > + if (error) { > + size_t i; > + > + for (i = 0; i < *n_fms; i++) { > + free((*fms)[i].ofpacts); > + } > + free(*fms); > + *fms = NULL; > + *n_fms = 0; > + > + return xasprintf("%s:%d: %s", file_name, line_number, error); > + } > *n_fms += 1; > } > ds_destroy(&s); > Should ds_destroy(&s) before return error message. > diff --git a/tests/learn.at b/tests/learn.at > index ec1c347..ce810b4 100644 > --- a/tests/learn.at > +++ b/tests/learn.at > @@ -75,11 +75,13 @@ AT_CHECK([[ovs-ofctl parse-flow > 'actions=learn(load:5->NXM_OF_IP_DST[])']], > [1], [], [stderr]) > AT_CHECK([sed -e 's/.*|meta_flow|WARN|//' < stderr], [0], > [[destination field ip_dst lacks correct prerequisites > +ovs-ofctl: actions are invalid with specified match (OFPBAC_BAD_ARGUMENT) > ]], [[]]) > AT_CHECK([[ovs-ofctl parse-flow > 'actions=learn(load:NXM_OF_IP_DST[]->NXM_NX_REG1[])']], > [1], [], [stderr]) > AT_CHECK([sed -e 's/.*|meta_flow|WARN|//' < stderr], [0], > [[source field ip_dst lacks correct prerequisites > +ovs-ofctl: actions are invalid with specified match (OFPBAC_BAD_ARGUMENT) > ]]) > AT_CLEANUP > Actually, I'm surprised by how few tests are modified. I'll do a scan again, after this patch is updated.
_______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev