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

Reply via email to